diff --git a/builtin/settingtypes.txt b/builtin/settingtypes.txt index 9a03285cb8..b06e105ce4 100644 --- a/builtin/settingtypes.txt +++ b/builtin/settingtypes.txt @@ -434,7 +434,6 @@ window_maximized (Window maximized) bool false # Save window size automatically when modified. # If true, screen size is saved in screen_w and screen_h, and whether the window # is maximized is stored in window_maximized. -# (Autosaving window_maximized only works if compiled with SDL.) # # Requires: desktop autosave_screensize (Remember screen size) bool true diff --git a/doc/compiling/README.md b/doc/compiling/README.md index 9ce8a800e9..152662491b 100644 --- a/doc/compiling/README.md +++ b/doc/compiling/README.md @@ -22,7 +22,6 @@ General options and their default values: MinSizeRel - Release build with -Os passed to compiler to make executable as small as possible PRECOMPILE_HEADERS=FALSE - Precompile some headers (experimental; requires CMake 3.16 or later) PRECOMPILED_HEADERS_PATH= - Path to a file listing all headers to precompile (default points to src/precompiled_headers.txt) - USE_SDL2=TRUE - Build with SDL2; Enables IrrlichtMt device SDL2 USE_SDL2_STATIC=TRUE - Links with SDL2::SDL2-static instead of SDL2::SDL2 ENABLE_CURL=ON - Build with cURL; Enables use of online mod repo, public serverlist and remote media fetching via http ENABLE_CURSES=ON - Build with (n)curses; Enables a server side terminal (command line option: --terminal) @@ -48,9 +47,9 @@ General options and their default values: Library specific options: - SDL2_DLL - Only if building with SDL2 on Windows; path to libSDL2.dll - SDL2_INCLUDE_DIRS - Only if building with SDL2; directory where SDL.h is located - SDL2_LIBRARIES - Only if building with SDL2; path to libSDL2.a/libSDL2.so/libSDL2.lib + SDL2_DLL - Only if building on Windows; path to libSDL2.dll + SDL2_INCLUDE_DIRS - directory where SDL.h is located + SDL2_LIBRARIES - path to libSDL2.a/libSDL2.so/libSDL2.lib CURL_DLL - Only if building with cURL on Windows; path to libcurl.dll CURL_INCLUDE_DIR - Only if building with cURL; directory where curl.h is located CURL_LIBRARY - Only if building with cURL; path to libcurl.a/libcurl.so/libcurl.lib diff --git a/irr/CMakeLists.txt b/irr/CMakeLists.txt index dfd6b189a4..f0ac7d2df0 100644 --- a/irr/CMakeLists.txt +++ b/irr/CMakeLists.txt @@ -2,8 +2,6 @@ cmake_minimum_required(VERSION 3.12) project(Irrlicht LANGUAGES CXX) -message(STATUS "*** Building IrrlichtMt ***") - set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD_REQUIRED ON) diff --git a/irr/README.md b/irr/README.md index eb7f14809f..f2c6c28636 100644 --- a/irr/README.md +++ b/irr/README.md @@ -1,5 +1,5 @@ -IrrlichtMt version 1.9 -====================== +IrrlichtMt +========== IrrlichtMt is the 3D engine of [Luanti](https://github.com/luanti-org). It is based on the [Irrlicht Engine](https://irrlicht.sourceforge.io/) but is now developed independently. @@ -14,16 +14,14 @@ The following libraries are required to be installed: * zlib, libPNG, libJPEG * OpenGL * or on mobile: OpenGL ES (can be optionally enabled on desktop too) -* on Unix: X11 -* SDL2 (see below) +* SDL2 Aside from standard search options (`ZLIB_INCLUDE_DIR`, `ZLIB_LIBRARY`, ...) the following options are available: * `ENABLE_OPENGL` - Enable OpenGL driver -* `ENABLE_OPENGL3` (default: `OFF`) - Enable OpenGL 3+ driver +* `ENABLE_OPENGL3` - Enable OpenGL 3+ driver * `ENABLE_GLES2` - Enable OpenGL ES 2+ driver -* `USE_SDL2` (default: platform-dependent, usually `ON`) - Use SDL2 instead of older native device code -However, IrrlichtMt cannot be built or installed separately. +**However, IrrlichtMt cannot be built or installed separately.** Platforms --------- @@ -36,27 +34,6 @@ We aim to support these platforms: This doesn't mean other platforms don't work or won't be supported, if you find something that doesn't work contributions are welcome. -Compatibility matrix --------------------- - -Driver (rows) vs Device (columns) - -| | SDL [1] | Linux [2] | OSX [3] | Win32 [4] | -|---------------------------|----------|----------------|------------------|-----------------| -| OpenGL 1.2 (to 2.1) | Works | Works (GLX) | Works (NSOpenGL) | Works (WGL) | -| OpenGL 3.2+ | Works | Testing (GLX) | Not implemented | Testing (WGL) | -| OpenGL ES 2.x | Works | Untested (EGL) | Not implemented | Untested (EGL) | -| WebGL 1 | Untested | Untested (EGL) | Not implemented | Not implemented | -| Null (no graphics output) | Works | Works | Works | Works | - -Notes: - -* [1] `CIrrDeviceSDL`: supports Android, Linux, macOS, Windows -* [2] `CIrrDeviceLinux`: supports Linux -* [3] `CIrrDeviceOSX`: supports macOS -* [4] `CIrrDeviceWin32`: supports Windows - - License ------- diff --git a/irr/include/EDeviceTypes.h b/irr/include/EDeviceTypes.h index c9188a1f27..6473728c2c 100644 --- a/irr/include/EDeviceTypes.h +++ b/irr/include/EDeviceTypes.h @@ -7,23 +7,14 @@ //! An enum for the different device types supported by the Irrlicht Engine. enum E_DEVICE_TYPE { - - //! A device native to Microsoft Windows - /** This device uses the Win32 API and works in all versions of Windows. */ EIDT_WIN32, - //! A device native to Unix style operating systems. - /** This device uses the X11 windowing system and works in Linux, Solaris, FreeBSD, OSX and - other operating systems which support X11. */ EIDT_X11, - //! A device native to Mac OSX - /** This device uses Apple's Cocoa API and works in Mac OSX 10.2 and above. */ EIDT_OSX, //! A device which uses Simple DirectMedia Layer - /** The SDL device works under all platforms supported by SDL but first must be compiled - in by setting the USE_SDL2 CMake option to ON */ + /** The SDL device works under all platforms supported by SDL. */ EIDT_SDL, //! This selection allows Irrlicht to choose the best device from the ones available. @@ -33,9 +24,5 @@ enum E_DEVICE_TYPE although it may not be able to render anything. */ EIDT_BEST, - //! A device for Android platforms - /** Best used with embedded devices and mobile systems. - Does not need X11 or other graphical subsystems. - May support hw-acceleration via OpenGL-ES */ EIDT_ANDROID, }; diff --git a/irr/include/SExposedVideoData.h b/irr/include/SExposedVideoData.h index fdeaa50807..7d158e9115 100644 --- a/irr/include/SExposedVideoData.h +++ b/irr/include/SExposedVideoData.h @@ -15,65 +15,7 @@ you are using the software or the null device. */ struct SExposedVideoData { - SExposedVideoData() - { - OpenGLWin32.HDc = 0; - OpenGLWin32.HRc = 0; - OpenGLWin32.HWnd = 0; - } - explicit SExposedVideoData(void *Window) - { - OpenGLWin32.HDc = 0; - OpenGLWin32.HRc = 0; - OpenGLWin32.HWnd = Window; - } - - struct SOpenGLWin32 - { - //! Private GDI Device Context. - /** Get if for example with: HDC h = reinterpret_cast(exposedData.OpenGLWin32.HDc) */ - void *HDc; - - //! Permanent Rendering Context. - /** Get if for example with: HGLRC h = reinterpret_cast(exposedData.OpenGLWin32.HRc) */ - void *HRc; - - //! Window handle. - /** Get with for example with: HWND h = reinterpret_cast(exposedData.OpenGLWin32.HWnd) */ - void *HWnd; - }; - - struct SOpenGLLinux - { - // XWindow handles - void *X11Display; - void *X11Context; - unsigned long X11Window; - unsigned long GLXWindow; - }; - - struct SOpenGLOSX - { - //! The NSOpenGLContext object. - void *Context; - - //! The NSWindow object. - void *Window; - }; - - struct SOGLESAndroid - { - //! The ANativeWindow object. - void *Window; - }; - - union - { - SOpenGLWin32 OpenGLWin32; - SOpenGLLinux OpenGLLinux; - SOpenGLOSX OpenGLOSX; - SOGLESAndroid OGLESAndroid; - }; + char dummy = 0; }; } // end namespace video diff --git a/irr/src/CEGLManager.cpp b/irr/src/CEGLManager.cpp index 5770ac3bb1..179bfb8995 100644 --- a/irr/src/CEGLManager.cpp +++ b/irr/src/CEGLManager.cpp @@ -35,16 +35,9 @@ bool CEGLManager::initialize(const SIrrlichtCreationParameters ¶ms, const SE return true; // Window is depend on platform. -#if defined(_IRR_COMPILE_WITH_WINDOWS_DEVICE_) - EglWindow = (NativeWindowType)Data.OpenGLWin32.HWnd; - Data.OpenGLWin32.HDc = GetDC((HWND)EglWindow); - EglDisplay = eglGetDisplay((NativeDisplayType)Data.OpenGLWin32.HDc); -#elif defined(_IRR_EMSCRIPTEN_PLATFORM_) +#if defined(_IRR_EMSCRIPTEN_PLATFORM_) EglWindow = 0; EglDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY); -#elif defined(_IRR_COMPILE_WITH_X11_DEVICE_) - EglWindow = (NativeWindowType)Data.OpenGLLinux.X11Window; - EglDisplay = eglGetDisplay((NativeDisplayType)Data.OpenGLLinux.X11Display); #endif // We must check if EGL display is valid. @@ -80,13 +73,6 @@ void CEGLManager::terminate() EglDisplay = EGL_NO_DISPLAY; } -#if defined(_IRR_COMPILE_WITH_WINDOWS_DEVICE_) - if (Data.OpenGLWin32.HDc) { - ReleaseDC((HWND)EglWindow, (HDC)Data.OpenGLWin32.HDc); - Data.OpenGLWin32.HDc = 0; - } -#endif - MajorVersion = 0; MinorVersion = 0; } diff --git a/irr/src/CGLXManager.cpp b/irr/src/CGLXManager.cpp deleted file mode 100644 index 93ec816322..0000000000 --- a/irr/src/CGLXManager.cpp +++ /dev/null @@ -1,394 +0,0 @@ -// Copyright (C) 2013 Christian Stehno -// This file is part of the "Irrlicht Engine". -// For conditions of distribution and use, see copyright notice in Irrlicht.h - -#include "CGLXManager.h" - -#ifdef _IRR_COMPILE_WITH_GLX_MANAGER_ - -#include "os.h" - -#define GL_GLEXT_LEGACY 1 -#define GLX_GLXEXT_LEGACY 1 -#include -#include -#include -#include - -namespace video -{ - -CGLXManager::CGLXManager(const SIrrlichtCreationParameters ¶ms, const SExposedVideoData &videodata, int screennr) : - Params(params), PrimaryContext(videodata), VisualInfo(0), glxFBConfig(0), GlxWin(0) -{ - CurrentContext.OpenGLLinux.X11Display = PrimaryContext.OpenGLLinux.X11Display; - - int major, minor; - Display *display = (Display *)PrimaryContext.OpenGLLinux.X11Display; - const bool isAvailableGLX = glXQueryExtension(display, &major, &minor); - - if (isAvailableGLX && glXQueryVersion(display, &major, &minor)) { -#if defined(GLX_VERSION_1_3) - typedef GLXFBConfig *(*PFNGLXCHOOSEFBCONFIGPROC)(Display *dpy, int screen, const int *attrib_list, int *nelements); - - PFNGLXCHOOSEFBCONFIGPROC glxChooseFBConfig = (PFNGLXCHOOSEFBCONFIGPROC)glXGetProcAddress(reinterpret_cast("glXChooseFBConfig")); - if (major == 1 && minor > 2 && glxChooseFBConfig) { - os::Printer::log("GLX >= 1.3", ELL_DEBUG); - // attribute array for the draw buffer - int visualAttrBuffer[] = { - GLX_RENDER_TYPE, - GLX_RGBA_BIT, - GLX_RED_SIZE, - 4, - GLX_GREEN_SIZE, - 4, - GLX_BLUE_SIZE, - 4, - GLX_ALPHA_SIZE, - Params.WithAlphaChannel ? 1 : 0, - GLX_DEPTH_SIZE, - Params.ZBufferBits, // 10,11 - GLX_DOUBLEBUFFER, - Params.Doublebuffer ? True : False, - GLX_STENCIL_SIZE, - Params.Stencilbuffer ? 1 : 0, -#if defined(GLX_VERSION_1_4) && defined(GLX_SAMPLE_BUFFERS) // we need to check the extension string! - GLX_SAMPLE_BUFFERS, - 1, - GLX_SAMPLES, - Params.AntiAlias, // 18,19 -#elif defined(GLX_ARB_multisample) - GLX_SAMPLE_BUFFERS_ARB, - 1, - GLX_SAMPLES_ARB, - Params.AntiAlias, // 18,19 -#elif defined(GLX_SGIS_multisample) - GLX_SAMPLE_BUFFERS_SGIS, - 1, - GLX_SAMPLES_SGIS, - Params.AntiAlias, // 18,19 -#endif - GLX_STEREO, - Params.Stereobuffer ? True : False, - None, - }; - - GLXFBConfig *configList = 0; - int nitems = 0; - if (Params.AntiAlias < 2) { - visualAttrBuffer[17] = 0; - visualAttrBuffer[19] = 0; - } - // first round with unchanged values - { - configList = glxChooseFBConfig(display, screennr, visualAttrBuffer, &nitems); - if (!configList && Params.AntiAlias) { - while (!configList && (visualAttrBuffer[19] > 1)) { - visualAttrBuffer[19] -= 1; - configList = glxChooseFBConfig(display, screennr, visualAttrBuffer, &nitems); - } - if (!configList) { - visualAttrBuffer[17] = 0; - visualAttrBuffer[19] = 0; - configList = glxChooseFBConfig(display, screennr, visualAttrBuffer, &nitems); - if (configList) { - os::Printer::log("No FSAA available.", ELL_WARNING); - Params.AntiAlias = 0; - } else { - // reenable multisampling - visualAttrBuffer[17] = 1; - visualAttrBuffer[19] = Params.AntiAlias; - } - } - } - } - // Next try with flipped stencil buffer value - // If the first round was with stencil flag it's now without - // Other way round also makes sense because some configs - // only have depth buffer combined with stencil buffer - if (!configList) { - if (Params.Stencilbuffer) - os::Printer::log("No stencilbuffer available, disabling stencil shadows.", ELL_WARNING); - Params.Stencilbuffer = !Params.Stencilbuffer; - visualAttrBuffer[15] = Params.Stencilbuffer ? 1 : 0; - - configList = glxChooseFBConfig(display, screennr, visualAttrBuffer, &nitems); - if (!configList && Params.AntiAlias) { - while (!configList && (visualAttrBuffer[19] > 1)) { - visualAttrBuffer[19] -= 1; - configList = glxChooseFBConfig(display, screennr, visualAttrBuffer, &nitems); - } - if (!configList) { - visualAttrBuffer[17] = 0; - visualAttrBuffer[19] = 0; - configList = glxChooseFBConfig(display, screennr, visualAttrBuffer, &nitems); - if (configList) { - os::Printer::log("No FSAA available.", ELL_WARNING); - Params.AntiAlias = 0; - } else { - // reenable multisampling - visualAttrBuffer[17] = 1; - visualAttrBuffer[19] = Params.AntiAlias; - } - } - } - } - // Next try without double buffer - if (!configList && Params.Doublebuffer) { - os::Printer::log("No doublebuffering available.", ELL_WARNING); - Params.Doublebuffer = false; - visualAttrBuffer[13] = GLX_DONT_CARE; - Params.Stencilbuffer = false; - visualAttrBuffer[15] = 0; - configList = glxChooseFBConfig(display, screennr, visualAttrBuffer, &nitems); - if (!configList && Params.AntiAlias) { - while (!configList && (visualAttrBuffer[19] > 1)) { - visualAttrBuffer[19] -= 1; - configList = glxChooseFBConfig(display, screennr, visualAttrBuffer, &nitems); - } - if (!configList) { - visualAttrBuffer[17] = 0; - visualAttrBuffer[19] = 0; - configList = glxChooseFBConfig(display, screennr, visualAttrBuffer, &nitems); - if (configList) { - os::Printer::log("No FSAA available.", ELL_WARNING); - Params.AntiAlias = 0; - } else { - // reenable multisampling - visualAttrBuffer[17] = 1; - visualAttrBuffer[19] = Params.AntiAlias; - } - } - } - } - if (configList) { - glxFBConfig = configList[0]; - XFree(configList); - typedef XVisualInfo *(*PFNGLXGETVISUALFROMFBCONFIGPROC)(Display *dpy, GLXFBConfig config); - PFNGLXGETVISUALFROMFBCONFIGPROC glxGetVisualFromFBConfig = (PFNGLXGETVISUALFROMFBCONFIGPROC)glXGetProcAddress(reinterpret_cast("glXGetVisualFromFBConfig")); - if (glxGetVisualFromFBConfig) - VisualInfo = glxGetVisualFromFBConfig(display, (GLXFBConfig)glxFBConfig); - } - } else -#endif - { - // attribute array for the draw buffer - int visualAttrBuffer[] = { - GLX_RGBA, GLX_USE_GL, - GLX_RED_SIZE, 4, - GLX_GREEN_SIZE, 4, - GLX_BLUE_SIZE, 4, - GLX_ALPHA_SIZE, Params.WithAlphaChannel ? 1 : 0, - GLX_DEPTH_SIZE, Params.ZBufferBits, - GLX_STENCIL_SIZE, Params.Stencilbuffer ? 1 : 0, // 12,13 - // The following attributes have no flags, but are - // either present or not. As a no-op we use - // GLX_USE_GL, which is silently ignored by glXChooseVisual - Params.Doublebuffer ? GLX_DOUBLEBUFFER : GLX_USE_GL, // 14 - Params.Stereobuffer ? GLX_STEREO : GLX_USE_GL, // 15 - None, - }; - - VisualInfo = glXChooseVisual(display, screennr, visualAttrBuffer); - if (!VisualInfo) { - if (Params.Stencilbuffer) - os::Printer::log("No stencilbuffer available, disabling.", ELL_WARNING); - Params.Stencilbuffer = !Params.Stencilbuffer; - visualAttrBuffer[13] = Params.Stencilbuffer ? 1 : 0; - - VisualInfo = glXChooseVisual(display, screennr, visualAttrBuffer); - if (!VisualInfo && Params.Doublebuffer) { - os::Printer::log("No doublebuffering available.", ELL_WARNING); - Params.Doublebuffer = false; - visualAttrBuffer[14] = GLX_USE_GL; - VisualInfo = glXChooseVisual(display, screennr, visualAttrBuffer); - } - } - } - } else - os::Printer::log("No GLX support available. OpenGL driver will not work.", ELL_WARNING); -} - -CGLXManager::~CGLXManager() -{ -} - -bool CGLXManager::initialize(const SIrrlichtCreationParameters ¶ms, const SExposedVideoData &videodata) -{ - // store params - Params = params; - - // set display - CurrentContext.OpenGLLinux.X11Display = videodata.OpenGLLinux.X11Display; - - // now get new window - CurrentContext.OpenGLLinux.X11Window = videodata.OpenGLLinux.X11Window; - if (!PrimaryContext.OpenGLLinux.X11Window) { - PrimaryContext.OpenGLLinux.X11Window = CurrentContext.OpenGLLinux.X11Window; - } - - return true; -} - -void CGLXManager::terminate() -{ - memset((void *)&CurrentContext, 0, sizeof(CurrentContext)); -} - -bool CGLXManager::generateSurface() -{ - if (glxFBConfig) { - GlxWin = glXCreateWindow((Display *)CurrentContext.OpenGLLinux.X11Display, (GLXFBConfig)glxFBConfig, CurrentContext.OpenGLLinux.X11Window, NULL); - if (!GlxWin) { - os::Printer::log("Could not create GLX window.", ELL_WARNING); - return false; - } - - CurrentContext.OpenGLLinux.GLXWindow = GlxWin; - } else { - CurrentContext.OpenGLLinux.GLXWindow = CurrentContext.OpenGLLinux.X11Window; - } - return true; -} - -void CGLXManager::destroySurface() -{ - if (GlxWin) - glXDestroyWindow((Display *)CurrentContext.OpenGLLinux.X11Display, GlxWin); -} - -#if defined(GLX_ARB_create_context) -static int IrrIgnoreError(Display *display, XErrorEvent *event) -{ - char msg[256]; - XGetErrorText(display, event->error_code, msg, 256); - os::Printer::log("Ignoring an X error", msg, ELL_DEBUG); - return 0; -} -#endif - -bool CGLXManager::generateContext() -{ - GLXContext context = 0; - - if (glxFBConfig) { - if (GlxWin) { -#if defined(GLX_ARB_create_context) - - PFNGLXCREATECONTEXTATTRIBSARBPROC glxCreateContextAttribsARB = (PFNGLXCREATECONTEXTATTRIBSARBPROC)glXGetProcAddress(reinterpret_cast("glXCreateContextAttribsARB")); - - if (glxCreateContextAttribsARB) { - os::Printer::log("GLX with GLX_ARB_create_context", ELL_DEBUG); - int contextAttrBuffer[] = { - GLX_CONTEXT_MAJOR_VERSION_ARB, 3, - GLX_CONTEXT_MINOR_VERSION_ARB, 0, - // GLX_CONTEXT_PROFILE_MASK_ARB, GLX_CONTEXT_CORE_PROFILE_BIT_ARB, - None}; - XErrorHandler old = XSetErrorHandler(IrrIgnoreError); - context = glxCreateContextAttribsARB((Display *)CurrentContext.OpenGLLinux.X11Display, (GLXFBConfig)glxFBConfig, NULL, True, contextAttrBuffer); - XSetErrorHandler(old); - // transparently fall back to legacy call - } - if (!context) -#endif - { - // create glx context - context = glXCreateNewContext((Display *)CurrentContext.OpenGLLinux.X11Display, (GLXFBConfig)glxFBConfig, GLX_RGBA_TYPE, NULL, True); - if (!context) { - os::Printer::log("Could not create GLX rendering context.", ELL_WARNING); - return false; - } - } - } else { - os::Printer::log("GLX window was not properly created.", ELL_WARNING); - return false; - } - } else { - context = glXCreateContext((Display *)CurrentContext.OpenGLLinux.X11Display, VisualInfo, NULL, True); - if (!context) { - os::Printer::log("Could not create GLX rendering context.", ELL_WARNING); - return false; - } - } - CurrentContext.OpenGLLinux.X11Context = context; - return true; -} - -const SExposedVideoData &CGLXManager::getContext() const -{ - return CurrentContext; -} - -bool CGLXManager::activateContext(const SExposedVideoData &videoData, bool restorePrimaryOnZero) -{ - // TODO: handle restorePrimaryOnZero - - if (videoData.OpenGLLinux.X11Window) { - if (videoData.OpenGLLinux.X11Display && videoData.OpenGLLinux.X11Context) { - if (!glXMakeCurrent((Display *)videoData.OpenGLLinux.X11Display, videoData.OpenGLLinux.GLXWindow, (GLXContext)videoData.OpenGLLinux.X11Context)) { - os::Printer::log("Context activation failed."); - return false; - } else { - CurrentContext.OpenGLLinux.GLXWindow = videoData.OpenGLLinux.GLXWindow; - CurrentContext.OpenGLLinux.X11Window = videoData.OpenGLLinux.X11Window; - CurrentContext.OpenGLLinux.X11Display = videoData.OpenGLLinux.X11Display; - } - } else { - // in case we only got a window ID, try with the existing values for display and context - if (!glXMakeCurrent((Display *)PrimaryContext.OpenGLLinux.X11Display, videoData.OpenGLLinux.GLXWindow, (GLXContext)PrimaryContext.OpenGLLinux.X11Context)) { - os::Printer::log("Context activation failed."); - return false; - } else { - CurrentContext.OpenGLLinux.GLXWindow = videoData.OpenGLLinux.GLXWindow; - CurrentContext.OpenGLLinux.X11Window = videoData.OpenGLLinux.X11Window; - CurrentContext.OpenGLLinux.X11Display = PrimaryContext.OpenGLLinux.X11Display; - } - } - } else if (!restorePrimaryOnZero && !videoData.OpenGLLinux.X11Window && !videoData.OpenGLLinux.X11Display) { - if (!glXMakeCurrent((Display *)PrimaryContext.OpenGLLinux.X11Display, None, NULL)) { - os::Printer::log("Render Context reset failed."); - return false; - } - CurrentContext.OpenGLLinux.X11Window = 0; - CurrentContext.OpenGLLinux.X11Display = 0; - } - // set back to main context - else if (CurrentContext.OpenGLLinux.X11Display != PrimaryContext.OpenGLLinux.X11Display) { - if (!glXMakeCurrent((Display *)PrimaryContext.OpenGLLinux.X11Display, PrimaryContext.OpenGLLinux.X11Window, (GLXContext)PrimaryContext.OpenGLLinux.X11Context)) { - os::Printer::log("Context activation failed."); - return false; - } else { - CurrentContext = PrimaryContext; - } - } - return true; -} - -void CGLXManager::destroyContext() -{ - if (CurrentContext.OpenGLLinux.X11Context) { - if (GlxWin) { - if (!glXMakeContextCurrent((Display *)CurrentContext.OpenGLLinux.X11Display, None, None, NULL)) - os::Printer::log("Could not release glx context.", ELL_WARNING); - } else { - if (!glXMakeCurrent((Display *)CurrentContext.OpenGLLinux.X11Display, None, NULL)) - os::Printer::log("Could not release glx context.", ELL_WARNING); - } - glXDestroyContext((Display *)CurrentContext.OpenGLLinux.X11Display, (GLXContext)CurrentContext.OpenGLLinux.X11Context); - } -} - -void *CGLXManager::getProcAddress(const std::string &procName) -{ - return (void *)glXGetProcAddressARB(reinterpret_cast(procName.c_str())); -} - -bool CGLXManager::swapBuffers() -{ - glXSwapBuffers((Display *)CurrentContext.OpenGLLinux.X11Display, CurrentContext.OpenGLLinux.GLXWindow); - return true; -} - -} - -#endif diff --git a/irr/src/CGLXManager.h b/irr/src/CGLXManager.h deleted file mode 100644 index f3e86e7ed1..0000000000 --- a/irr/src/CGLXManager.h +++ /dev/null @@ -1,73 +0,0 @@ -// Copyright (C) 2013 Christian Stehno -// This file is part of the "Irrlicht Engine". -// For conditions of distribution and use, see copyright notice in Irrlicht.h - -#pragma once - -#ifdef _IRR_COMPILE_WITH_GLX_MANAGER_ - -#include "SIrrCreationParameters.h" -#include "SExposedVideoData.h" -#include "IContextManager.h" -#include "SColor.h" -#include -#include - -// we can't include glx.h here, because gl.h has incompatible types with ogl es headers and it -// cause redefinition errors, thats why we use ugly trick with void* types and casts. - -namespace video -{ -// GLX manager. -class CGLXManager : public IContextManager -{ -public: - //! Constructor. - CGLXManager(const SIrrlichtCreationParameters ¶ms, const SExposedVideoData &videodata, int screennr); - - //! Destructor - ~CGLXManager(); - - // Initialize - bool initialize(const SIrrlichtCreationParameters ¶ms, const SExposedVideoData &data) override; - - // Terminate - void terminate() override; - - // Create surface. - bool generateSurface() override; - - // Destroy surface. - void destroySurface() override; - - // Create context. - bool generateContext() override; - - // Destroy context. - void destroyContext() override; - - //! Get current context - const SExposedVideoData &getContext() const override; - - //! Change render context, disable old and activate new defined by videoData - bool activateContext(const SExposedVideoData &videoData, bool restorePrimaryOnZero) override; - - // Get procedure address. - void *getProcAddress(const std::string &procName) override; - - // Swap buffers. - bool swapBuffers() override; - - XVisualInfo *getVisual() const { return VisualInfo; } // return XVisualInfo - -private: - SIrrlichtCreationParameters Params; - SExposedVideoData PrimaryContext; - SExposedVideoData CurrentContext; - XVisualInfo *VisualInfo; - void *glxFBConfig; // GLXFBConfig - XID GlxWin; // GLXWindow -}; -} - -#endif diff --git a/irr/src/CIrrDeviceLinux.cpp b/irr/src/CIrrDeviceLinux.cpp deleted file mode 100644 index 3ec9e6481f..0000000000 --- a/irr/src/CIrrDeviceLinux.cpp +++ /dev/null @@ -1,2217 +0,0 @@ -// Copyright (C) 2002-2012 Nikolaus Gebhardt -// This file is part of the "Irrlicht Engine". -// For conditions of distribution and use, see copyright notice in irrlicht.h - -#include "CIrrDeviceLinux.h" - -#ifdef _IRR_COMPILE_WITH_X11_DEVICE_ - -#include -#include -#include -#include -#include -#include "IEventReceiver.h" -#include "ISceneManager.h" -#include "IGUIElement.h" -#include "IGUIEnvironment.h" -#include "os.h" -#include "CTimer.h" -#include "irrString.h" -#include "Keycodes.h" -#include "COSOperator.h" -#include "CColorConverter.h" -#include "SIrrCreationParameters.h" -#include "SExposedVideoData.h" -#include "IGUISpriteBank.h" -#include "IImageLoader.h" -#include "IFileSystem.h" -#include "IVideoDriver.h" -#include -#include - -#if defined(_IRR_LINUX_X11_XINPUT2_) -#include -#endif - -#if defined(_IRR_COMPILE_WITH_OGLES2_) -#include "CEGLManager.h" -#endif - -#if defined(_IRR_COMPILE_WITH_GLX_MANAGER_) -#include "CGLXManager.h" -#endif - -#ifdef _IRR_LINUX_XCURSOR_ -#include -#endif - -#if defined(_IRR_COMPILE_WITH_X11_) || defined(_IRR_COMPILE_WITH_JOYSTICK_EVENTS_) -#include -#endif - -#if defined _IRR_COMPILE_WITH_JOYSTICK_EVENTS_ -#include - -#ifdef __FreeBSD__ -#include -#else - -// linux/joystick.h includes linux/input.h, which #defines values for various KEY_FOO keys. -// These override the KEY_FOO equivalents, which stops key handling from working. -// As a workaround, defining _INPUT_H stops linux/input.h from being included; it -// doesn't actually seem to be necessary except to pull in sys/ioctl.h. -#define _INPUT_H -#include // Would normally be included in linux/input.h -#include -#undef _INPUT_H -#endif - -#endif // _IRR_COMPILE_WITH_JOYSTICK_EVENTS_ - -namespace -{ -Atom X_ATOM_CLIPBOARD; -Atom X_ATOM_TARGETS; -Atom X_ATOM_UTF8_STRING; -Atom X_ATOM_UTF8_MIME_TYPE; -Atom X_ATOM_TEXT; -Atom X_ATOM_NETWM_MAXIMIZE_VERT; -Atom X_ATOM_NETWM_MAXIMIZE_HORZ; -Atom X_ATOM_NETWM_STATE; -Atom X_ATOM_NETWM_STATE_FULLSCREEN; - -Atom X_ATOM_WM_DELETE_WINDOW; - -#if defined(_IRR_LINUX_X11_XINPUT2_) -int XI_EXTENSIONS_OPCODE; -#endif -} - -//! constructor -CIrrDeviceLinux::CIrrDeviceLinux(const SIrrlichtCreationParameters ¶m) : - CIrrDeviceStub(param), -#ifdef _IRR_COMPILE_WITH_X11_ - XDisplay(0), VisualInfo(0), Screennr(0), XWindow(0), StdHints(0), - XInputMethod(0), XInputContext(0), - HasNetWM(false), -#endif -#if defined(_IRR_LINUX_X11_XINPUT2_) - currentTouchedCount(0), -#endif - Width(param.WindowSize.Width), Height(param.WindowSize.Height), - WindowHasFocus(false), WindowMinimized(false), WindowMaximized(param.WindowMaximized), - ExternalWindow(false), AutorepeatSupport(0) -{ - // print version, distribution etc. - // thx to LynxLuna for pointing me to the uname function - core::stringc linuxversion; - struct utsname LinuxInfo; - uname(&LinuxInfo); - - linuxversion += LinuxInfo.sysname; - linuxversion += " "; - linuxversion += LinuxInfo.release; - linuxversion += " "; - linuxversion += LinuxInfo.version; - linuxversion += " "; - linuxversion += LinuxInfo.machine; - - Operator = new COSOperator(linuxversion, this); - os::Printer::log(linuxversion.c_str(), ELL_INFORMATION); - - // create keymap - createKeyMap(); - - // initialize X11 thread safety - // libX11 1.8+ has this on by default - // without it, multi-threaded GL drivers may crash - XInitThreads(); - - // create window - if (CreationParams.DriverType != video::EDT_NULL) { - // create the window, only if we do not use the null device - if (!createWindow()) - return; - if (param.WindowResizable < 2) - setResizable(param.WindowResizable == 1 ? true : false); -#ifdef _IRR_COMPILE_WITH_X11_ - createInputContext(); -#endif - } - - // create cursor control - CursorControl = new CCursorControl(this, CreationParams.DriverType == video::EDT_NULL); - - // create driver - createDriver(); - - if (!VideoDriver) - return; - - createGUIAndScene(); - - if (param.WindowMaximized) - maximizeWindow(); - - setupTopLevelXorgWindow(); -} - -//! destructor -CIrrDeviceLinux::~CIrrDeviceLinux() -{ -#ifdef _IRR_COMPILE_WITH_X11_ - if (StdHints) - XFree(StdHints); - // Disable cursor (it is drop'ed in stub) - if (CursorControl) { - CursorControl->setVisible(false); - static_cast(CursorControl)->clearCursors(); - } - - // Must free OpenGL textures etc before destroying context, so can't wait for stub destructor - if (GUIEnvironment) { - GUIEnvironment->drop(); - GUIEnvironment = NULL; - } - if (SceneManager) { - SceneManager->drop(); - SceneManager = NULL; - } - if (VideoDriver) { - VideoDriver->drop(); - VideoDriver = NULL; - } - - destroyInputContext(); - - if (XDisplay) { - if (ContextManager) { - ContextManager->destroyContext(); - ContextManager->destroySurface(); - } - - if (!ExternalWindow) { - XDestroyWindow(XDisplay, XWindow); - XCloseDisplay(XDisplay); - } - } - if (VisualInfo) - XFree(VisualInfo); - -#endif // #ifdef _IRR_COMPILE_WITH_X11_ - -#if defined(_IRR_COMPILE_WITH_JOYSTICK_EVENTS_) - for (u32 joystick = 0; joystick < ActiveJoysticks.size(); ++joystick) { - if (ActiveJoysticks[joystick].fd >= 0) { - close(ActiveJoysticks[joystick].fd); - } - } -#endif -} - -#if defined(_IRR_COMPILE_WITH_X11_) && defined(_DEBUG) -int IrrPrintXError(Display *display, XErrorEvent *event) -{ - char msg[256]; - char msg2[256]; - - snprintf_irr(msg, 256, "%d", event->request_code); - XGetErrorDatabaseText(display, "XRequest", msg, "unknown", msg2, 256); - XGetErrorText(display, event->error_code, msg, 256); - os::Printer::log("X Error", msg, ELL_WARNING); - os::Printer::log("From call ", msg2, ELL_WARNING); - return 0; -} -#endif - -bool CIrrDeviceLinux::switchToFullscreen() -{ - if (!CreationParams.Fullscreen) - return true; - - if (!HasNetWM) { - os::Printer::log("NetWM support is required to allow Irrlicht to switch " - "to fullscreen mode. Running in windowed mode instead.", - ELL_WARNING); - CreationParams.Fullscreen = false; - return false; - } - - XEvent ev = {0}; - - ev.type = ClientMessage; - ev.xclient.window = XWindow; - ev.xclient.message_type = X_ATOM_NETWM_STATE; - ev.xclient.format = 32; - ev.xclient.data.l[0] = 1; // _NET_WM_STATE_ADD - ev.xclient.data.l[1] = X_ATOM_NETWM_STATE_FULLSCREEN; - - XSendEvent(XDisplay, DefaultRootWindow(XDisplay), false, - SubstructureNotifyMask | SubstructureRedirectMask, &ev); - - return true; -} - -void CIrrDeviceLinux::setupTopLevelXorgWindow() -{ -#ifdef _IRR_COMPILE_WITH_X11_ - if (CreationParams.DriverType == video::EDT_NULL) - return; // no display and window - - os::Printer::log("Configuring X11-specific top level window properties", ELL_DEBUG); - - // Set application name and class hints. For now name and class are the same. - // Note: SDL uses the executable name here (i.e. "luanti"). - XClassHint *classhint = XAllocClassHint(); - classhint->res_name = const_cast("Luanti"); - classhint->res_class = const_cast("Luanti"); - - XSetClassHint(XDisplay, XWindow, classhint); - XFree(classhint); - - // FIXME: In the future WMNormalHints should be set ... e.g see the - // gtk/gdk code (gdk/x11/gdksurface-x11.c) for the setup_top_level - // method. But for now (as it would require some significant changes) - // leave the code as is. - - // The following is borrowed from the above gdk source for setting top - // level windows. The source indicates and the Xlib docs suggest that - // this will set the WM_CLIENT_MACHINE and WM_LOCAL_NAME. This will not - // set the WM_CLIENT_MACHINE to a Fully Qualified Domain Name (FQDN) which is - // required by the Extended Window Manager Hints (EWMH) spec when setting - // the _NET_WM_PID (see further down) but running Minetest in an env - // where the window manager is on another machine from Minetest (therefore - // making the PID useless) is not expected to be a problem. Further - // more, using gtk/gdk as the model it would seem that not using a FQDN is - // not an issue for modern Xorg window managers. - - os::Printer::log("Setting Xorg window manager Properties", ELL_DEBUG); - - XSetWMProperties(XDisplay, XWindow, NULL, NULL, NULL, 0, NULL, NULL, NULL); - - // Set the _NET_WM_PID window property according to the EWMH spec. _NET_WM_PID - // (in conjunction with WM_CLIENT_MACHINE) can be used by window managers to - // force a shutdown of an application if it doesn't respond to the destroy - // window message. - - os::Printer::log("Setting Xorg _NET_WM_PID extended window manager property", ELL_DEBUG); - - Atom NET_WM_PID = XInternAtom(XDisplay, "_NET_WM_PID", false); - - long pid = static_cast(getpid()); - - XChangeProperty(XDisplay, XWindow, NET_WM_PID, - XA_CARDINAL, 32, PropModeReplace, - reinterpret_cast(&pid), 1); - - // Set the WM_CLIENT_LEADER window property here. Minetest has only one - // window and that window will always be the leader. - - os::Printer::log("Setting Xorg WM_CLIENT_LEADER property", ELL_DEBUG); - - Atom WM_CLIENT_LEADER = XInternAtom(XDisplay, "WM_CLIENT_LEADER", false); - - XChangeProperty(XDisplay, XWindow, WM_CLIENT_LEADER, - XA_WINDOW, 32, PropModeReplace, - reinterpret_cast(&XWindow), 1); -#endif -} - -#if defined(_IRR_COMPILE_WITH_X11_) -void IrrPrintXGrabError(int grabResult, const c8 *grabCommand) -{ - if (grabResult == GrabSuccess) { - // os::Printer::log(grabCommand, "GrabSuccess", ELL_INFORMATION); - return; - } - - switch (grabResult) { - case AlreadyGrabbed: - os::Printer::log(grabCommand, "AlreadyGrabbed", ELL_WARNING); - break; - case GrabNotViewable: - os::Printer::log(grabCommand, "GrabNotViewable", ELL_WARNING); - break; - case GrabFrozen: - os::Printer::log(grabCommand, "GrabFrozen", ELL_WARNING); - break; - case GrabInvalidTime: - os::Printer::log(grabCommand, "GrabInvalidTime", ELL_WARNING); - break; - default: - os::Printer::log(grabCommand, "grab failed with unknown problem", ELL_WARNING); - break; - } -} -#endif - -bool CIrrDeviceLinux::createWindow() -{ -#ifdef _IRR_COMPILE_WITH_X11_ -#ifdef _DEBUG - os::Printer::log("Creating X window...", ELL_INFORMATION); - XSetErrorHandler(IrrPrintXError); -#endif - - XDisplay = XOpenDisplay(0); - if (!XDisplay) { - os::Printer::log("Error: Need running XServer to start Irrlicht Engine.", ELL_ERROR); - if (XDisplayName(0)[0]) - os::Printer::log("Could not open display", XDisplayName(0), ELL_ERROR); - else - os::Printer::log("Could not open display, set DISPLAY variable", ELL_ERROR); - return false; - } - - Screennr = DefaultScreen(XDisplay); - - initXAtoms(); - - // check netwm support - Atom WMCheck = XInternAtom(XDisplay, "_NET_SUPPORTING_WM_CHECK", True); - if (WMCheck != None) - HasNetWM = true; - -#if defined(_IRR_COMPILE_WITH_GLX_MANAGER_) - // don't use the XVisual with OpenGL, because it ignores all requested - // properties of the CreationParams - if (CreationParams.DriverType == video::EDT_OPENGL - || CreationParams.DriverType == video::EDT_OPENGL3) { - video::SExposedVideoData data; - data.OpenGLLinux.X11Display = XDisplay; - ContextManager = new video::CGLXManager(CreationParams, data, Screennr); - VisualInfo = ((video::CGLXManager *)ContextManager)->getVisual(); - } -#endif - - if (!VisualInfo) { - // create visual with standard X methods - os::Printer::log("Using plain X visual"); - XVisualInfo visTempl; // Template to hold requested values - int visNumber; // Return value of available visuals - - visTempl.screen = Screennr; - // ARGB visuals should be avoided for usual applications - visTempl.depth = CreationParams.WithAlphaChannel ? 32 : 24; - while ((!VisualInfo) && (visTempl.depth >= 16)) { - VisualInfo = XGetVisualInfo(XDisplay, VisualScreenMask | VisualDepthMask, - &visTempl, &visNumber); - visTempl.depth -= 8; - } - } - - if (!VisualInfo) { - os::Printer::log("Fatal error, could not get visual.", ELL_ERROR); - XCloseDisplay(XDisplay); - XDisplay = 0; - return false; - } -#ifdef _DEBUG - else - os::Printer::log("Visual chosen", core::stringc(static_cast(VisualInfo->visualid)).c_str(), ELL_DEBUG); -#endif - - // create color map - Colormap colormap; - colormap = XCreateColormap(XDisplay, - RootWindow(XDisplay, VisualInfo->screen), - VisualInfo->visual, AllocNone); - - WndAttributes.colormap = colormap; - WndAttributes.border_pixel = 0; - WndAttributes.event_mask = StructureNotifyMask | FocusChangeMask | ExposureMask; - WndAttributes.event_mask |= PointerMotionMask | - ButtonPressMask | KeyPressMask | - ButtonReleaseMask | KeyReleaseMask; - - if (!CreationParams.WindowId) { - int x = 0; - int y = 0; - - if (!CreationParams.Fullscreen) { - if (CreationParams.WindowPosition.X > 0) - x = CreationParams.WindowPosition.X; - if (CreationParams.WindowPosition.Y > 0) - y = CreationParams.WindowPosition.Y; - } - - // create new Window - // Remove window manager decoration in fullscreen - XWindow = XCreateWindow(XDisplay, - RootWindow(XDisplay, VisualInfo->screen), - x, y, Width, Height, 0, VisualInfo->depth, - InputOutput, VisualInfo->visual, - CWBorderPixel | CWColormap | CWEventMask, - &WndAttributes); - - XMapRaised(XDisplay, XWindow); - CreationParams.WindowId = (void *)XWindow; - X_ATOM_WM_DELETE_WINDOW = XInternAtom(XDisplay, "WM_DELETE_WINDOW", True); - XSetWMProtocols(XDisplay, XWindow, &X_ATOM_WM_DELETE_WINDOW, 1); - - if (CreationParams.Fullscreen) { - // Don't try to set window position - } else if (CreationParams.WindowPosition.X >= 0 || CreationParams.WindowPosition.Y >= 0) { // default is -1, -1 - // Window managers are free to ignore positions above, so give it another shot - XMoveWindow(XDisplay, XWindow, x, y); - } - } else { - // attach external window - XWindow = (Window)CreationParams.WindowId; - { - // Note: This might be further improved by using a InputOnly window instead of InputOutput. - // I think then it should be possible to render into the given parent window instead of - // creating a child-window. - // Also... this does possibly leak. - Window child_window = XCreateWindow(XDisplay, - XWindow, - 0, 0, Width, Height, 0, VisualInfo->depth, - InputOutput, VisualInfo->visual, - CWBorderPixel | CWColormap | CWEventMask, - &WndAttributes); - - // do not forget to map new window - XMapWindow(XDisplay, child_window); - - // overwrite device window id - XWindow = child_window; - } - XWindowAttributes wa; - XGetWindowAttributes(XDisplay, XWindow, &wa); - CreationParams.WindowSize.Width = wa.width; - CreationParams.WindowSize.Height = wa.height; - CreationParams.Fullscreen = false; - ExternalWindow = true; - } - - switchToFullscreen(); - - WindowMinimized = false; - XkbSetDetectableAutoRepeat(XDisplay, True, &AutorepeatSupport); - - Window tmp; - u32 borderWidth; - int x, y; - unsigned int bits; - - XGetGeometry(XDisplay, XWindow, &tmp, &x, &y, &Width, &Height, &borderWidth, &bits); - CreationParams.Bits = bits; - CreationParams.WindowSize.Width = Width; - CreationParams.WindowSize.Height = Height; - - StdHints = XAllocSizeHints(); - long num; - XGetWMNormalHints(XDisplay, XWindow, StdHints, &num); - - initXInput2(); - -#endif // #ifdef _IRR_COMPILE_WITH_X11_ - return true; -} - -//! create the driver -void CIrrDeviceLinux::createDriver() -{ - switch (CreationParams.DriverType) { -#ifdef _IRR_COMPILE_WITH_X11_ - case video::EDT_OPENGL: - { -#ifdef _IRR_COMPILE_WITH_OPENGL_ - video::SExposedVideoData data; - data.OpenGLLinux.X11Window = XWindow; - data.OpenGLLinux.X11Display = XDisplay; - - ContextManager->initialize(CreationParams, data); -#endif - VideoDriver = video::createOpenGLDriver(CreationParams, FileSystem, ContextManager); - } - break; - case video::EDT_OPENGL3: - { -#ifdef ENABLE_OPENGL3 - video::SExposedVideoData data; - data.OpenGLLinux.X11Window = XWindow; - data.OpenGLLinux.X11Display = XDisplay; - - ContextManager->initialize(CreationParams, data); -#endif - VideoDriver = video::createOpenGL3Driver(CreationParams, FileSystem, ContextManager); - } - break; - case video::EDT_OGLES2: - { -#ifdef _IRR_COMPILE_WITH_OGLES2_ - video::SExposedVideoData data; - data.OpenGLLinux.X11Window = XWindow; - data.OpenGLLinux.X11Display = XDisplay; - - ContextManager = new video::CEGLManager(); - ContextManager->initialize(CreationParams, data); -#endif - VideoDriver = video::createOGLES2Driver(CreationParams, FileSystem, ContextManager); - } - break; - case video::EDT_WEBGL1: - { -#ifdef _IRR_COMPILE_WITH_WEBGL1_ - video::SExposedVideoData data; - data.OpenGLLinux.X11Window = XWindow; - data.OpenGLLinux.X11Display = XDisplay; - - ContextManager = new video::CEGLManager(); - ContextManager->initialize(CreationParams, data); -#endif - VideoDriver = video::createWebGL1Driver(CreationParams, FileSystem, ContextManager); - } - break; - case video::EDT_NULL: - VideoDriver = video::createNullDriver(FileSystem, CreationParams.WindowSize); - break; - default: - os::Printer::log("Unable to create video driver of unknown type.", ELL_ERROR); - break; -#else // no X11 - case video::EDT_NULL: - VideoDriver = video::createNullDriver(FileSystem, CreationParams.WindowSize); - break; - default: - os::Printer::log("No X11 support compiled in. Only Null driver available.", ELL_ERROR); - break; -#endif - } -} - -#ifdef _IRR_COMPILE_WITH_X11_ -bool CIrrDeviceLinux::createInputContext() -{ - // One one side it would be nicer to let users do that - on the other hand - // not setting the environment locale will not work when using i18n X11 functions. - // So users would have to call it always or their input is broken badly. - // We can restore immediately - so won't mess with anything in users apps. - core::stringc oldLocale(setlocale(LC_CTYPE, NULL)); - setlocale(LC_CTYPE, ""); // use environment locale - - if (!XSupportsLocale()) { - os::Printer::log("Locale not supported. Falling back to non-i18n input.", ELL_WARNING); - setlocale(LC_CTYPE, oldLocale.c_str()); - return false; - } - - // Load XMODIFIERS (e.g. for IMEs) - if (!XSetLocaleModifiers("")) { - setlocale(LC_CTYPE, oldLocale.c_str()); - os::Printer::log("XSetLocaleModifiers failed. Falling back to non-i18n input.", ELL_WARNING); - return false; - } - - XInputMethod = XOpenIM(XDisplay, NULL, NULL, NULL); - if (!XInputMethod) { - setlocale(LC_CTYPE, oldLocale.c_str()); - os::Printer::log("XOpenIM failed to create an input method. Falling back to non-i18n input.", ELL_WARNING); - return false; - } - - XIMStyles *im_supported_styles; - XGetIMValues(XInputMethod, XNQueryInputStyle, &im_supported_styles, (char *)NULL); - XIMStyle bestStyle = 0; - XIMStyle supportedStyle = XIMPreeditNothing | XIMStatusNothing; - for (int i = 0; i < im_supported_styles->count_styles; ++i) { - XIMStyle style = im_supported_styles->supported_styles[i]; - if ((style & supportedStyle) == style) /* if we can handle it */ - { - bestStyle = style; - break; - } - } - XFree(im_supported_styles); - - if (!bestStyle) { - XDestroyIC(XInputContext); - XInputContext = 0; - - os::Printer::log("XInputMethod has no input style we can use. Falling back to non-i18n input.", ELL_WARNING); - setlocale(LC_CTYPE, oldLocale.c_str()); - return false; - } - - XInputContext = XCreateIC(XInputMethod, - XNInputStyle, bestStyle, - XNClientWindow, XWindow, - (char *)NULL); - if (!XInputContext) { - os::Printer::log("XInputContext failed to create an input context. Falling back to non-i18n input.", ELL_WARNING); - setlocale(LC_CTYPE, oldLocale.c_str()); - return false; - } - XSetICFocus(XInputContext); - setlocale(LC_CTYPE, oldLocale.c_str()); - return true; -} - -void CIrrDeviceLinux::destroyInputContext() -{ - if (XInputContext) { - XUnsetICFocus(XInputContext); - XDestroyIC(XInputContext); - XInputContext = 0; - } - if (XInputMethod) { - XCloseIM(XInputMethod); - XInputMethod = 0; - } -} - -EKEY_CODE CIrrDeviceLinux::getKeyCode(XEvent &event) -{ - EKEY_CODE keyCode = (EKEY_CODE)0; - - SKeyMap mp; - mp.X11Key = XkbKeycodeToKeysym(XDisplay, event.xkey.keycode, 0, 0); - const s32 idx = KeyMap.binary_search(mp); - if (idx != -1) { - keyCode = (EKEY_CODE)KeyMap[idx].Win32Key; - } - if (keyCode == 0) { - keyCode = KEY_UNKNOWN; - if (!mp.X11Key) { - os::Printer::log("No such X11Key, event keycode", core::stringc(event.xkey.keycode).c_str(), ELL_INFORMATION); - } else if (idx == -1) { - os::Printer::log("EKEY_CODE not found, X11 keycode", core::stringc(mp.X11Key).c_str(), ELL_INFORMATION); - } else { - os::Printer::log("EKEY_CODE is 0, X11 keycode", core::stringc(mp.X11Key).c_str(), ELL_INFORMATION); - } - } - return keyCode; -} -#endif - -//! runs the device. Returns false if device wants to be deleted -bool CIrrDeviceLinux::run() -{ - os::Timer::tick(); - -#ifdef _IRR_COMPILE_WITH_X11_ - - if (CursorControl) - static_cast(CursorControl)->update(); - - if ((CreationParams.DriverType != video::EDT_NULL) && XDisplay) { - SEvent irrevent; - irrevent.MouseInput.ButtonStates = 0xffffffff; - - while (XPending(XDisplay) > 0 && !Close) { - XEvent event; - XNextEvent(XDisplay, &event); - if (XFilterEvent(&event, None)) - continue; - - switch (event.type) { - case ConfigureNotify: - // check for changed window size - if ((event.xconfigure.width != (int)Width) || - (event.xconfigure.height != (int)Height)) { - Width = event.xconfigure.width; - Height = event.xconfigure.height; - - if (VideoDriver) - VideoDriver->OnResize(core::dimension2d(Width, Height)); - } - break; - - case MapNotify: - WindowMinimized = false; - break; - - case UnmapNotify: - WindowMinimized = true; - break; - - case FocusIn: - WindowHasFocus = true; - break; - - case FocusOut: - WindowHasFocus = false; - break; - - case MotionNotify: - irrevent.EventType = EET_MOUSE_INPUT_EVENT; - irrevent.MouseInput.Event = EMIE_MOUSE_MOVED; - irrevent.MouseInput.X = event.xbutton.x; - irrevent.MouseInput.Y = event.xbutton.y; - irrevent.MouseInput.Control = (event.xkey.state & ControlMask) != 0; - irrevent.MouseInput.Shift = (event.xkey.state & ShiftMask) != 0; - - // mouse button states - irrevent.MouseInput.ButtonStates = (event.xbutton.state & Button1Mask) ? EMBSM_LEFT : 0; - irrevent.MouseInput.ButtonStates |= (event.xbutton.state & Button3Mask) ? EMBSM_RIGHT : 0; - irrevent.MouseInput.ButtonStates |= (event.xbutton.state & Button2Mask) ? EMBSM_MIDDLE : 0; - - postEventFromUser(irrevent); - break; - - case ButtonPress: - case ButtonRelease: - - irrevent.EventType = EET_MOUSE_INPUT_EVENT; - irrevent.MouseInput.X = event.xbutton.x; - irrevent.MouseInput.Y = event.xbutton.y; - irrevent.MouseInput.Control = (event.xkey.state & ControlMask) != 0; - irrevent.MouseInput.Shift = (event.xkey.state & ShiftMask) != 0; - - // mouse button states - // This sets the state which the buttons had _prior_ to the event. - // So unlike on Windows the button which just got changed has still the old state here. - // We handle that below by flipping the corresponding bit later. - irrevent.MouseInput.ButtonStates = (event.xbutton.state & Button1Mask) ? EMBSM_LEFT : 0; - irrevent.MouseInput.ButtonStates |= (event.xbutton.state & Button3Mask) ? EMBSM_RIGHT : 0; - irrevent.MouseInput.ButtonStates |= (event.xbutton.state & Button2Mask) ? EMBSM_MIDDLE : 0; - - irrevent.MouseInput.Event = EMIE_COUNT; - - switch (event.xbutton.button) { - case Button1: - irrevent.MouseInput.Event = - (event.type == ButtonPress) ? EMIE_LMOUSE_PRESSED_DOWN : EMIE_LMOUSE_LEFT_UP; - irrevent.MouseInput.ButtonStates ^= EMBSM_LEFT; - break; - - case Button3: - irrevent.MouseInput.Event = - (event.type == ButtonPress) ? EMIE_RMOUSE_PRESSED_DOWN : EMIE_RMOUSE_LEFT_UP; - irrevent.MouseInput.ButtonStates ^= EMBSM_RIGHT; - break; - - case Button2: - irrevent.MouseInput.Event = - (event.type == ButtonPress) ? EMIE_MMOUSE_PRESSED_DOWN : EMIE_MMOUSE_LEFT_UP; - irrevent.MouseInput.ButtonStates ^= EMBSM_MIDDLE; - break; - - case Button4: - if (event.type == ButtonPress) { - irrevent.MouseInput.Event = EMIE_MOUSE_WHEEL; - irrevent.MouseInput.Wheel = 1.0f; - } - break; - - case Button5: - if (event.type == ButtonPress) { - irrevent.MouseInput.Event = EMIE_MOUSE_WHEEL; - irrevent.MouseInput.Wheel = -1.0f; - } - break; - } - - if (irrevent.MouseInput.Event != EMIE_COUNT) { - postEventFromUser(irrevent); - - if (irrevent.MouseInput.Event >= EMIE_LMOUSE_PRESSED_DOWN && irrevent.MouseInput.Event <= EMIE_MMOUSE_PRESSED_DOWN) { - u32 clicks = checkSuccessiveClicks(irrevent.MouseInput.X, irrevent.MouseInput.Y, irrevent.MouseInput.Event); - if (clicks == 2) { - irrevent.MouseInput.Event = (EMOUSE_INPUT_EVENT)(EMIE_LMOUSE_DOUBLE_CLICK + irrevent.MouseInput.Event - EMIE_LMOUSE_PRESSED_DOWN); - postEventFromUser(irrevent); - } else if (clicks == 3) { - irrevent.MouseInput.Event = (EMOUSE_INPUT_EVENT)(EMIE_LMOUSE_TRIPLE_CLICK + irrevent.MouseInput.Event - EMIE_LMOUSE_PRESSED_DOWN); - postEventFromUser(irrevent); - } - } - } - break; - - case MappingNotify: - XRefreshKeyboardMapping(&event.xmapping); - break; - - case KeyRelease: - if (0 == AutorepeatSupport && (XPending(XDisplay) > 0)) { - // check for Autorepeat manually - // We'll do the same as Windows does: Only send KeyPressed - // So every KeyRelease is a real release - XEvent next_event; - XPeekEvent(event.xkey.display, &next_event); - if ((next_event.type == KeyPress) && - (next_event.xkey.keycode == event.xkey.keycode) && - (next_event.xkey.time - event.xkey.time) < 2) // usually same time, but on some systems a difference of 1 is possible - { - // Ignore the key release event - break; - } - } - - irrevent.EventType = EET_KEY_INPUT_EVENT; - irrevent.KeyInput.PressedDown = false; - irrevent.KeyInput.Char = 0; // on release that's undefined - irrevent.KeyInput.Control = (event.xkey.state & ControlMask) != 0; - irrevent.KeyInput.Shift = (event.xkey.state & ShiftMask) != 0; - irrevent.KeyInput.Key = getKeyCode(event); - - postEventFromUser(irrevent); - break; - - case KeyPress: { - SKeyMap mp; - if (XInputContext) { - wchar_t buf[64] = {0}; - Status status; - int strLen = XwcLookupString(XInputContext, &event.xkey, buf, sizeof(buf) / sizeof(wchar_t) - 1, &mp.X11Key, &status); - if (status == XBufferOverflow) { - os::Printer::log("XwcLookupString needs a larger buffer", ELL_INFORMATION); - } - if (strLen > 0 && (status == XLookupChars || status == XLookupBoth)) { - if (strLen > 1) { - // Multiple characters: send string event - irrevent.EventType = EET_STRING_INPUT_EVENT; - irrevent.StringInput.Str = new core::stringw(buf); - postEventFromUser(irrevent); - delete irrevent.StringInput.Str; - irrevent.StringInput.Str = NULL; - break; - } else { - irrevent.KeyInput.Char = buf[0]; - } - } else { -#if 0 // Most of those are fine - but useful to have the info when debugging Irrlicht itself. - if ( status == XLookupNone ) - os::Printer::log("XLookupNone", ELL_INFORMATION); - else if ( status == XLookupKeySym ) - // Getting this also when user did not set setlocale(LC_ALL, ""); and using an unknown locale - // XSupportsLocale doesn't seem to catch that unfortunately - any other ideas to catch it are welcome. - os::Printer::log("XLookupKeySym", ELL_INFORMATION); - else if ( status == XBufferOverflow ) - os::Printer::log("XBufferOverflow", ELL_INFORMATION); - else if ( strLen == 0 ) - os::Printer::log("no string", ELL_INFORMATION); -#endif - irrevent.KeyInput.Char = 0; - } - } else // Old version without InputContext. Does not support i18n, but good to have as fallback. - { - union - { - char buf[8]; - wchar_t wbuf[2]; - } tmp = {{0}}; - XLookupString(&event.xkey, tmp.buf, sizeof(tmp.buf), &mp.X11Key, NULL); - irrevent.KeyInput.Char = tmp.wbuf[0]; - } - - irrevent.EventType = EET_KEY_INPUT_EVENT; - irrevent.KeyInput.PressedDown = true; - irrevent.KeyInput.Control = (event.xkey.state & ControlMask) != 0; - irrevent.KeyInput.Shift = (event.xkey.state & ShiftMask) != 0; - irrevent.KeyInput.Key = getKeyCode(event); - postEventFromUser(irrevent); - } break; - - case ClientMessage: { - if (static_cast(event.xclient.data.l[0]) == X_ATOM_WM_DELETE_WINDOW && X_ATOM_WM_DELETE_WINDOW != None) { - os::Printer::log("Quit message received.", ELL_INFORMATION); - Close = true; - } else { - // we assume it's a user message - irrevent.EventType = EET_USER_EVENT; - irrevent.UserEvent.UserData1 = static_cast(event.xclient.data.l[0]); - irrevent.UserEvent.UserData2 = static_cast(event.xclient.data.l[1]); - postEventFromUser(irrevent); - } - } break; - - case SelectionRequest: { - XSelectionRequestEvent *req = &(event.xselectionrequest); - - auto send_response = [this, req](Atom property) { - XEvent response; - response.xselection.type = SelectionNotify; - response.xselection.display = req->display; - response.xselection.requestor = req->requestor; - response.xselection.selection = req->selection; - response.xselection.target = req->target; - response.xselection.property = property; - response.xselection.time = req->time; - XSendEvent(XDisplay, req->requestor, 0, 0, &response); - XFlush(XDisplay); - }; - auto send_response_refuse = [&send_response] { - send_response(None); - }; - - // sets the required property to data of type type and - // sends the according response - auto set_property_and_notify = [this, req, &send_response](Atom type, int format, const void *data, u32 data_size) { - XChangeProperty(XDisplay, - req->requestor, - req->property, - type, - format, - PropModeReplace, - (const unsigned char *)data, - data_size); - send_response(req->property); - }; - - if ((req->selection != X_ATOM_CLIPBOARD && - req->selection != XA_PRIMARY) || - req->owner != XWindow) { - // we are not the owner, refuse request - send_response_refuse(); - break; - } - const core::stringc &text_buffer = req->selection == X_ATOM_CLIPBOARD ? Clipboard : PrimarySelection; - - // for debugging: - //~ { - //~ char *target_name = XGetAtomName(XDisplay, req->target); - //~ fprintf(stderr, "CIrrDeviceLinux::run: target: %s (=%ld)\n", - //~ target_name, req->target); - //~ XFree(target_name); - //~ } - - if (req->property == None) { - // req is from obsolete client, use target as property name - // and X_ATOM_UTF8_STRING as type - // Note: this was not tested and might be incorrect - os::Printer::log("CIrrDeviceLinux::run: SelectionRequest from obsolete client", - ELL_WARNING); - XChangeProperty(XDisplay, - req->requestor, - req->target, X_ATOM_UTF8_STRING, - 8, // format = 8-bit - PropModeReplace, - (unsigned char *)text_buffer.c_str(), - text_buffer.size()); - send_response(req->target); - break; - } - - if (req->target == X_ATOM_TARGETS) { - Atom data[] = { - X_ATOM_TARGETS, - X_ATOM_TEXT, - X_ATOM_UTF8_STRING, - X_ATOM_UTF8_MIME_TYPE}; - set_property_and_notify( - XA_ATOM, - 32, // Atom is long, we need to set 32 for longs - &data, - sizeof(data) / sizeof(*data)); - - } else if (req->target == X_ATOM_TEXT || - req->target == X_ATOM_UTF8_STRING || - req->target == X_ATOM_UTF8_MIME_TYPE) { - set_property_and_notify( - X_ATOM_UTF8_STRING, - 8, - text_buffer.c_str(), - text_buffer.size()); - - } else { - // refuse the request - send_response_refuse(); - } - } break; - -#if defined(_IRR_LINUX_X11_XINPUT2_) - case GenericEvent: { - XGenericEventCookie *cookie = &event.xcookie; - if (XGetEventData(XDisplay, cookie) && cookie->extension == XI_EXTENSIONS_OPCODE && XI_EXTENSIONS_OPCODE && (cookie->evtype == XI_TouchUpdate || cookie->evtype == XI_TouchBegin || cookie->evtype == XI_TouchEnd)) { - XIDeviceEvent *de = (XIDeviceEvent *)cookie->data; - - irrevent.EventType = EET_TOUCH_INPUT_EVENT; - - irrevent.TouchInput.Event = cookie->evtype == XI_TouchUpdate ? ETIE_MOVED : (cookie->evtype == XI_TouchBegin ? ETIE_PRESSED_DOWN : ETIE_LEFT_UP); - - irrevent.TouchInput.ID = de->detail; - irrevent.TouchInput.X = de->event_x; - irrevent.TouchInput.Y = de->event_y; - - if (irrevent.TouchInput.Event == ETIE_PRESSED_DOWN) { - currentTouchedCount++; - } - irrevent.TouchInput.touchedCount = currentTouchedCount; - if (currentTouchedCount > 0 && irrevent.TouchInput.Event == ETIE_LEFT_UP) { - currentTouchedCount--; - } - - postEventFromUser(irrevent); - } - } break; -#endif - - default: - break; - } // end switch - - // Update IME information - if (XInputContext && GUIEnvironment) { - gui::IGUIElement *elem = GUIEnvironment->getFocus(); - if (elem && elem->acceptsIME()) { - core::rect r = elem->getAbsolutePosition(); - XPoint p; - p.x = (short)r.UpperLeftCorner.X; - p.y = (short)r.LowerRightCorner.Y; - XSetICFocus(XInputContext); - XVaNestedList l = XVaCreateNestedList(0, XNSpotLocation, &p, NULL); - XSetICValues(XInputContext, XNPreeditAttributes, l, NULL); - XFree(l); - } else { - XUnsetICFocus(XInputContext); - } - } - - } // end while - } -#endif //_IRR_COMPILE_WITH_X11_ - - if (!Close) - pollJoysticks(); - - return !Close; -} - -//! Pause the current process for the minimum time allowed only to allow other processes to execute -void CIrrDeviceLinux::yield() -{ - struct timespec ts = {0, 1}; - nanosleep(&ts, NULL); -} - -//! Pause execution and let other processes to run for a specified amount of time. -void CIrrDeviceLinux::sleep(u32 timeMs, bool pauseTimer = false) -{ - const bool wasStopped = Timer ? Timer->isStopped() : true; - - struct timespec ts; - ts.tv_sec = (time_t)(timeMs / 1000); - ts.tv_nsec = (long)(timeMs % 1000) * 1000000; - - if (pauseTimer && !wasStopped) - Timer->stop(); - - nanosleep(&ts, NULL); - - if (pauseTimer && !wasStopped) - Timer->start(); -} - -//! sets the caption of the window -void CIrrDeviceLinux::setWindowCaption(const wchar_t *text) -{ -#ifdef _IRR_COMPILE_WITH_X11_ - if (CreationParams.DriverType == video::EDT_NULL) - return; - - XTextProperty txt; - if (Success == XwcTextListToTextProperty(XDisplay, const_cast(&text), - 1, XStdICCTextStyle, &txt)) { - XSetWMName(XDisplay, XWindow, &txt); - XSetWMIconName(XDisplay, XWindow, &txt); - XFree(txt.value); - } -#endif -} - -//! Sets the window icon. -bool CIrrDeviceLinux::setWindowIcon(const video::IImage *img) -{ - if (CreationParams.DriverType == video::EDT_NULL) - return false; // no display and window - - u32 height = img->getDimension().Height; - u32 width = img->getDimension().Width; - - size_t icon_buffer_len = 2 + height * width; - long *icon_buffer = new long[icon_buffer_len]; - - icon_buffer[0] = width; - icon_buffer[1] = height; - - for (u32 x = 0; x < width; x++) { - for (u32 y = 0; y < height; y++) { - video::SColor col = img->getPixel(x, y); - long pixel_val = 0; - pixel_val |= (u8)col.getAlpha() << 24; - pixel_val |= (u8)col.getRed() << 16; - pixel_val |= (u8)col.getGreen() << 8; - pixel_val |= (u8)col.getBlue(); - icon_buffer[2 + x + y * width] = pixel_val; - } - } - - if (XDisplay == NULL) { - os::Printer::log("Could not find x11 display for setting its icon.", ELL_ERROR); - delete[] icon_buffer; - return false; - } - - Atom net_wm_icon = XInternAtom(XDisplay, "_NET_WM_ICON", False); - Atom cardinal = XInternAtom(XDisplay, "CARDINAL", False); - XChangeProperty(XDisplay, XWindow, net_wm_icon, cardinal, 32, PropModeReplace, - (const unsigned char *)icon_buffer, icon_buffer_len); - - delete[] icon_buffer; - - return true; -} - -//! notifies the device that it should close itself -void CIrrDeviceLinux::closeDevice() -{ - Close = true; -} - -//! returns if window is active. if not, nothing need to be drawn -bool CIrrDeviceLinux::isWindowActive() const -{ - return (WindowHasFocus && !WindowMinimized); -} - -//! returns if window has focus. -bool CIrrDeviceLinux::isWindowFocused() const -{ - return WindowHasFocus; -} - -//! returns if window is minimized. -bool CIrrDeviceLinux::isWindowMinimized() const -{ - return WindowMinimized; -} - -//! returns last state from maximizeWindow() and restoreWindow() -bool CIrrDeviceLinux::isWindowMaximized() const -{ - return WindowMaximized; -} - -//! Checks if the Irrlicht device supports touch events. -bool CIrrDeviceLinux::supportsTouchEvents() const -{ -#if defined(_IRR_LINUX_X11_XINPUT2_) - return true; -#else - return false; -#endif -} - - -//! returns color format of the window. -video::ECOLOR_FORMAT CIrrDeviceLinux::getColorFormat() const -{ -#ifdef _IRR_COMPILE_WITH_X11_ - if (VisualInfo && (VisualInfo->depth != 16)) - return video::ECF_R8G8B8; - else -#endif - return video::ECF_R5G6B5; -} - -//! Sets if the window should be resizable in windowed mode. -void CIrrDeviceLinux::setResizable(bool resize) -{ -#ifdef _IRR_COMPILE_WITH_X11_ - if (CreationParams.DriverType == video::EDT_NULL || CreationParams.Fullscreen) - return; - - if (!resize) { - // Must be heap memory because data size depends on X Server - XSizeHints *hints = XAllocSizeHints(); - hints->flags = PSize | PMinSize | PMaxSize; - hints->min_width = hints->max_width = hints->base_width = Width; - hints->min_height = hints->max_height = hints->base_height = Height; - XSetWMNormalHints(XDisplay, XWindow, hints); - XFree(hints); - } else { - XSetWMNormalHints(XDisplay, XWindow, StdHints); - } - XFlush(XDisplay); -#endif // #ifdef _IRR_COMPILE_WITH_X11_ -} - -//! Resize the render window. -void CIrrDeviceLinux::setWindowSize(const core::dimension2d &size) -{ -#ifdef _IRR_COMPILE_WITH_X11_ - if (CreationParams.DriverType == video::EDT_NULL || CreationParams.Fullscreen) - return; - - XWindowChanges values; - values.width = size.Width; - values.height = size.Height; - XConfigureWindow(XDisplay, XWindow, CWWidth | CWHeight, &values); - XFlush(XDisplay); -#endif // #ifdef _IRR_COMPILE_WITH_X11_ -} - -//! Minimize window -void CIrrDeviceLinux::minimizeWindow() -{ -#ifdef _IRR_COMPILE_WITH_X11_ - XIconifyWindow(XDisplay, XWindow, Screennr); -#endif -} - -//! Maximize window -void CIrrDeviceLinux::maximizeWindow() -{ -#ifdef _IRR_COMPILE_WITH_X11_ - // Maximize is not implemented in bare X, it's a WM construct. - if (HasNetWM) { - XEvent ev = {0}; - - ev.type = ClientMessage; - ev.xclient.window = XWindow; - ev.xclient.message_type = X_ATOM_NETWM_STATE; - ev.xclient.format = 32; - ev.xclient.data.l[0] = 1; // _NET_WM_STATE_ADD - ev.xclient.data.l[1] = X_ATOM_NETWM_MAXIMIZE_VERT; - ev.xclient.data.l[2] = X_ATOM_NETWM_MAXIMIZE_HORZ; - - XSendEvent(XDisplay, DefaultRootWindow(XDisplay), false, - SubstructureNotifyMask | SubstructureRedirectMask, &ev); - } - - XMapWindow(XDisplay, XWindow); - - WindowMaximized = true; -#endif -} - -//! Restore original window size -void CIrrDeviceLinux::restoreWindow() -{ -#ifdef _IRR_COMPILE_WITH_X11_ - // Maximize is not implemented in bare X, it's a WM construct. - if (HasNetWM) { - XEvent ev = {0}; - - ev.type = ClientMessage; - ev.xclient.window = XWindow; - ev.xclient.message_type = X_ATOM_NETWM_STATE; - ev.xclient.format = 32; - ev.xclient.data.l[0] = 0; // _NET_WM_STATE_REMOVE - ev.xclient.data.l[1] = X_ATOM_NETWM_MAXIMIZE_VERT; - ev.xclient.data.l[2] = X_ATOM_NETWM_MAXIMIZE_HORZ; - - XSendEvent(XDisplay, DefaultRootWindow(XDisplay), false, - SubstructureNotifyMask | SubstructureRedirectMask, &ev); - } - - XMapWindow(XDisplay, XWindow); - - WindowMaximized = false; -#endif -} - -core::position2di CIrrDeviceLinux::getWindowPosition() -{ - int wx = 0, wy = 0; -#ifdef _IRR_COMPILE_WITH_X11_ - Window child; - XTranslateCoordinates(XDisplay, XWindow, DefaultRootWindow(XDisplay), 0, 0, &wx, &wy, &child); -#endif - return core::position2di(wx, wy); -} - -void CIrrDeviceLinux::createKeyMap() -{ - // I don't know if this is the best method to create - // the lookuptable, but I'll leave it like that until - // I find a better version. - // Search for missing numbers in keysymdef.h - -#ifdef _IRR_COMPILE_WITH_X11_ - KeyMap.reallocate(190); - KeyMap.push_back(SKeyMap(XK_BackSpace, KEY_BACK)); - KeyMap.push_back(SKeyMap(XK_Tab, KEY_TAB)); - KeyMap.push_back(SKeyMap(XK_ISO_Left_Tab, KEY_TAB)); - KeyMap.push_back(SKeyMap(XK_Linefeed, 0)); // ??? - KeyMap.push_back(SKeyMap(XK_Clear, KEY_CLEAR)); - KeyMap.push_back(SKeyMap(XK_Return, KEY_RETURN)); - KeyMap.push_back(SKeyMap(XK_Pause, KEY_PAUSE)); - KeyMap.push_back(SKeyMap(XK_Scroll_Lock, KEY_SCROLL)); - KeyMap.push_back(SKeyMap(XK_Sys_Req, 0)); // ??? - KeyMap.push_back(SKeyMap(XK_Escape, KEY_ESCAPE)); - KeyMap.push_back(SKeyMap(XK_Insert, KEY_INSERT)); - KeyMap.push_back(SKeyMap(XK_Delete, KEY_DELETE)); - KeyMap.push_back(SKeyMap(XK_Home, KEY_HOME)); - KeyMap.push_back(SKeyMap(XK_Left, KEY_LEFT)); - KeyMap.push_back(SKeyMap(XK_Up, KEY_UP)); - KeyMap.push_back(SKeyMap(XK_Right, KEY_RIGHT)); - KeyMap.push_back(SKeyMap(XK_Down, KEY_DOWN)); - KeyMap.push_back(SKeyMap(XK_Prior, KEY_PRIOR)); - KeyMap.push_back(SKeyMap(XK_Page_Up, KEY_PRIOR)); - KeyMap.push_back(SKeyMap(XK_Next, KEY_NEXT)); - KeyMap.push_back(SKeyMap(XK_Page_Down, KEY_NEXT)); - KeyMap.push_back(SKeyMap(XK_End, KEY_END)); - KeyMap.push_back(SKeyMap(XK_Begin, KEY_NUMPAD5)); - KeyMap.push_back(SKeyMap(XK_Num_Lock, KEY_NUMLOCK)); - KeyMap.push_back(SKeyMap(XK_KP_Space, KEY_SPACE)); - KeyMap.push_back(SKeyMap(XK_KP_Tab, KEY_TAB)); - KeyMap.push_back(SKeyMap(XK_KP_Enter, KEY_RETURN)); - KeyMap.push_back(SKeyMap(XK_KP_F1, KEY_F1)); - KeyMap.push_back(SKeyMap(XK_KP_F2, KEY_F2)); - KeyMap.push_back(SKeyMap(XK_KP_F3, KEY_F3)); - KeyMap.push_back(SKeyMap(XK_KP_F4, KEY_F4)); - KeyMap.push_back(SKeyMap(XK_KP_Home, KEY_HOME)); - KeyMap.push_back(SKeyMap(XK_KP_Left, KEY_LEFT)); - KeyMap.push_back(SKeyMap(XK_KP_Up, KEY_UP)); - KeyMap.push_back(SKeyMap(XK_KP_Right, KEY_RIGHT)); - KeyMap.push_back(SKeyMap(XK_KP_Down, KEY_DOWN)); - KeyMap.push_back(SKeyMap(XK_Print, KEY_PRINT)); - KeyMap.push_back(SKeyMap(XK_KP_Prior, KEY_PRIOR)); - KeyMap.push_back(SKeyMap(XK_KP_Page_Up, KEY_PRIOR)); - KeyMap.push_back(SKeyMap(XK_KP_Next, KEY_NEXT)); - KeyMap.push_back(SKeyMap(XK_KP_Page_Down, KEY_NEXT)); - KeyMap.push_back(SKeyMap(XK_KP_End, KEY_END)); - KeyMap.push_back(SKeyMap(XK_KP_Begin, KEY_NUMPAD5)); - KeyMap.push_back(SKeyMap(XK_KP_Insert, KEY_INSERT)); - KeyMap.push_back(SKeyMap(XK_KP_Delete, KEY_DELETE)); - KeyMap.push_back(SKeyMap(XK_KP_Equal, 0)); // ??? - KeyMap.push_back(SKeyMap(XK_KP_Multiply, KEY_MULTIPLY)); - KeyMap.push_back(SKeyMap(XK_KP_Add, KEY_ADD)); - KeyMap.push_back(SKeyMap(XK_KP_Separator, KEY_SEPARATOR)); - KeyMap.push_back(SKeyMap(XK_KP_Subtract, KEY_SUBTRACT)); - KeyMap.push_back(SKeyMap(XK_KP_Decimal, KEY_DECIMAL)); - KeyMap.push_back(SKeyMap(XK_KP_Divide, KEY_DIVIDE)); - KeyMap.push_back(SKeyMap(XK_KP_0, KEY_NUMPAD0)); - KeyMap.push_back(SKeyMap(XK_KP_1, KEY_NUMPAD1)); - KeyMap.push_back(SKeyMap(XK_KP_2, KEY_NUMPAD2)); - KeyMap.push_back(SKeyMap(XK_KP_3, KEY_NUMPAD3)); - KeyMap.push_back(SKeyMap(XK_KP_4, KEY_NUMPAD4)); - KeyMap.push_back(SKeyMap(XK_KP_5, KEY_NUMPAD5)); - KeyMap.push_back(SKeyMap(XK_KP_6, KEY_NUMPAD6)); - KeyMap.push_back(SKeyMap(XK_KP_7, KEY_NUMPAD7)); - KeyMap.push_back(SKeyMap(XK_KP_8, KEY_NUMPAD8)); - KeyMap.push_back(SKeyMap(XK_KP_9, KEY_NUMPAD9)); - KeyMap.push_back(SKeyMap(XK_F1, KEY_F1)); - KeyMap.push_back(SKeyMap(XK_F2, KEY_F2)); - KeyMap.push_back(SKeyMap(XK_F3, KEY_F3)); - KeyMap.push_back(SKeyMap(XK_F4, KEY_F4)); - KeyMap.push_back(SKeyMap(XK_F5, KEY_F5)); - KeyMap.push_back(SKeyMap(XK_F6, KEY_F6)); - KeyMap.push_back(SKeyMap(XK_F7, KEY_F7)); - KeyMap.push_back(SKeyMap(XK_F8, KEY_F8)); - KeyMap.push_back(SKeyMap(XK_F9, KEY_F9)); - KeyMap.push_back(SKeyMap(XK_F10, KEY_F10)); - KeyMap.push_back(SKeyMap(XK_F11, KEY_F11)); - KeyMap.push_back(SKeyMap(XK_F12, KEY_F12)); - KeyMap.push_back(SKeyMap(XK_Shift_L, KEY_LSHIFT)); - KeyMap.push_back(SKeyMap(XK_Shift_R, KEY_RSHIFT)); - KeyMap.push_back(SKeyMap(XK_Control_L, KEY_LCONTROL)); - KeyMap.push_back(SKeyMap(XK_Control_R, KEY_RCONTROL)); - KeyMap.push_back(SKeyMap(XK_Caps_Lock, KEY_CAPITAL)); - KeyMap.push_back(SKeyMap(XK_Shift_Lock, KEY_CAPITAL)); - KeyMap.push_back(SKeyMap(XK_Meta_L, KEY_LWIN)); - KeyMap.push_back(SKeyMap(XK_Meta_R, KEY_RWIN)); - KeyMap.push_back(SKeyMap(XK_Alt_L, KEY_LMENU)); - KeyMap.push_back(SKeyMap(XK_Alt_R, KEY_RMENU)); - KeyMap.push_back(SKeyMap(XK_ISO_Level3_Shift, KEY_RMENU)); - KeyMap.push_back(SKeyMap(XK_Menu, KEY_MENU)); - KeyMap.push_back(SKeyMap(XK_space, KEY_SPACE)); - KeyMap.push_back(SKeyMap(XK_exclam, 0)); //? - KeyMap.push_back(SKeyMap(XK_quotedbl, 0)); //? - KeyMap.push_back(SKeyMap(XK_section, 0)); //? - KeyMap.push_back(SKeyMap(XK_numbersign, KEY_OEM_2)); - KeyMap.push_back(SKeyMap(XK_dollar, 0)); //? - KeyMap.push_back(SKeyMap(XK_percent, 0)); //? - KeyMap.push_back(SKeyMap(XK_ampersand, 0)); //? - KeyMap.push_back(SKeyMap(XK_apostrophe, KEY_OEM_7)); - KeyMap.push_back(SKeyMap(XK_parenleft, 0)); //? - KeyMap.push_back(SKeyMap(XK_parenright, 0)); //? - KeyMap.push_back(SKeyMap(XK_asterisk, 0)); //? - KeyMap.push_back(SKeyMap(XK_plus, KEY_PLUS)); //? - KeyMap.push_back(SKeyMap(XK_comma, KEY_COMMA)); //? - KeyMap.push_back(SKeyMap(XK_minus, KEY_MINUS)); //? - KeyMap.push_back(SKeyMap(XK_period, KEY_PERIOD)); //? - KeyMap.push_back(SKeyMap(XK_slash, KEY_OEM_2)); //? - KeyMap.push_back(SKeyMap(XK_0, KEY_KEY_0)); - KeyMap.push_back(SKeyMap(XK_1, KEY_KEY_1)); - KeyMap.push_back(SKeyMap(XK_2, KEY_KEY_2)); - KeyMap.push_back(SKeyMap(XK_3, KEY_KEY_3)); - KeyMap.push_back(SKeyMap(XK_4, KEY_KEY_4)); - KeyMap.push_back(SKeyMap(XK_5, KEY_KEY_5)); - KeyMap.push_back(SKeyMap(XK_6, KEY_KEY_6)); - KeyMap.push_back(SKeyMap(XK_7, KEY_KEY_7)); - KeyMap.push_back(SKeyMap(XK_8, KEY_KEY_8)); - KeyMap.push_back(SKeyMap(XK_9, KEY_KEY_9)); - KeyMap.push_back(SKeyMap(XK_colon, 0)); //? - KeyMap.push_back(SKeyMap(XK_semicolon, KEY_OEM_1)); - KeyMap.push_back(SKeyMap(XK_less, KEY_OEM_102)); - KeyMap.push_back(SKeyMap(XK_equal, KEY_PLUS)); - KeyMap.push_back(SKeyMap(XK_greater, 0)); //? - KeyMap.push_back(SKeyMap(XK_question, 0)); //? - KeyMap.push_back(SKeyMap(XK_at, KEY_KEY_2)); //? - KeyMap.push_back(SKeyMap(XK_mu, 0)); //? - KeyMap.push_back(SKeyMap(XK_EuroSign, 0)); //? - KeyMap.push_back(SKeyMap(XK_A, KEY_KEY_A)); - KeyMap.push_back(SKeyMap(XK_B, KEY_KEY_B)); - KeyMap.push_back(SKeyMap(XK_C, KEY_KEY_C)); - KeyMap.push_back(SKeyMap(XK_D, KEY_KEY_D)); - KeyMap.push_back(SKeyMap(XK_E, KEY_KEY_E)); - KeyMap.push_back(SKeyMap(XK_F, KEY_KEY_F)); - KeyMap.push_back(SKeyMap(XK_G, KEY_KEY_G)); - KeyMap.push_back(SKeyMap(XK_H, KEY_KEY_H)); - KeyMap.push_back(SKeyMap(XK_I, KEY_KEY_I)); - KeyMap.push_back(SKeyMap(XK_J, KEY_KEY_J)); - KeyMap.push_back(SKeyMap(XK_K, KEY_KEY_K)); - KeyMap.push_back(SKeyMap(XK_L, KEY_KEY_L)); - KeyMap.push_back(SKeyMap(XK_M, KEY_KEY_M)); - KeyMap.push_back(SKeyMap(XK_N, KEY_KEY_N)); - KeyMap.push_back(SKeyMap(XK_O, KEY_KEY_O)); - KeyMap.push_back(SKeyMap(XK_P, KEY_KEY_P)); - KeyMap.push_back(SKeyMap(XK_Q, KEY_KEY_Q)); - KeyMap.push_back(SKeyMap(XK_R, KEY_KEY_R)); - KeyMap.push_back(SKeyMap(XK_S, KEY_KEY_S)); - KeyMap.push_back(SKeyMap(XK_T, KEY_KEY_T)); - KeyMap.push_back(SKeyMap(XK_U, KEY_KEY_U)); - KeyMap.push_back(SKeyMap(XK_V, KEY_KEY_V)); - KeyMap.push_back(SKeyMap(XK_W, KEY_KEY_W)); - KeyMap.push_back(SKeyMap(XK_X, KEY_KEY_X)); - KeyMap.push_back(SKeyMap(XK_Y, KEY_KEY_Y)); - KeyMap.push_back(SKeyMap(XK_Z, KEY_KEY_Z)); - KeyMap.push_back(SKeyMap(XK_bracketleft, KEY_OEM_4)); - KeyMap.push_back(SKeyMap(XK_backslash, KEY_OEM_5)); - KeyMap.push_back(SKeyMap(XK_bracketright, KEY_OEM_6)); - KeyMap.push_back(SKeyMap(XK_asciicircum, KEY_OEM_5)); - KeyMap.push_back(SKeyMap(XK_dead_circumflex, KEY_OEM_5)); - KeyMap.push_back(SKeyMap(XK_degree, 0)); //? - KeyMap.push_back(SKeyMap(XK_underscore, KEY_MINUS)); //? - KeyMap.push_back(SKeyMap(XK_grave, KEY_OEM_3)); - KeyMap.push_back(SKeyMap(XK_dead_grave, KEY_OEM_3)); - KeyMap.push_back(SKeyMap(XK_acute, KEY_OEM_6)); - KeyMap.push_back(SKeyMap(XK_dead_acute, KEY_OEM_6)); - KeyMap.push_back(SKeyMap(XK_a, KEY_KEY_A)); - KeyMap.push_back(SKeyMap(XK_b, KEY_KEY_B)); - KeyMap.push_back(SKeyMap(XK_c, KEY_KEY_C)); - KeyMap.push_back(SKeyMap(XK_d, KEY_KEY_D)); - KeyMap.push_back(SKeyMap(XK_e, KEY_KEY_E)); - KeyMap.push_back(SKeyMap(XK_f, KEY_KEY_F)); - KeyMap.push_back(SKeyMap(XK_g, KEY_KEY_G)); - KeyMap.push_back(SKeyMap(XK_h, KEY_KEY_H)); - KeyMap.push_back(SKeyMap(XK_i, KEY_KEY_I)); - KeyMap.push_back(SKeyMap(XK_j, KEY_KEY_J)); - KeyMap.push_back(SKeyMap(XK_k, KEY_KEY_K)); - KeyMap.push_back(SKeyMap(XK_l, KEY_KEY_L)); - KeyMap.push_back(SKeyMap(XK_m, KEY_KEY_M)); - KeyMap.push_back(SKeyMap(XK_n, KEY_KEY_N)); - KeyMap.push_back(SKeyMap(XK_o, KEY_KEY_O)); - KeyMap.push_back(SKeyMap(XK_p, KEY_KEY_P)); - KeyMap.push_back(SKeyMap(XK_q, KEY_KEY_Q)); - KeyMap.push_back(SKeyMap(XK_r, KEY_KEY_R)); - KeyMap.push_back(SKeyMap(XK_s, KEY_KEY_S)); - KeyMap.push_back(SKeyMap(XK_t, KEY_KEY_T)); - KeyMap.push_back(SKeyMap(XK_u, KEY_KEY_U)); - KeyMap.push_back(SKeyMap(XK_v, KEY_KEY_V)); - KeyMap.push_back(SKeyMap(XK_w, KEY_KEY_W)); - KeyMap.push_back(SKeyMap(XK_x, KEY_KEY_X)); - KeyMap.push_back(SKeyMap(XK_y, KEY_KEY_Y)); - KeyMap.push_back(SKeyMap(XK_z, KEY_KEY_Z)); - KeyMap.push_back(SKeyMap(XK_ssharp, KEY_OEM_4)); - KeyMap.push_back(SKeyMap(XK_adiaeresis, KEY_OEM_7)); - KeyMap.push_back(SKeyMap(XK_odiaeresis, KEY_OEM_3)); - KeyMap.push_back(SKeyMap(XK_udiaeresis, KEY_OEM_1)); - KeyMap.push_back(SKeyMap(XK_Super_L, KEY_LWIN)); - KeyMap.push_back(SKeyMap(XK_Super_R, KEY_RWIN)); - - KeyMap.sort(); -#endif -} - -bool CIrrDeviceLinux::activateJoysticks(core::array &joystickInfo) -{ -#if defined(_IRR_COMPILE_WITH_JOYSTICK_EVENTS_) - - joystickInfo.clear(); - - u32 joystick; - for (joystick = 0; joystick < 32; ++joystick) { - // The joystick device could be here... - core::stringc devName = "/dev/js"; - devName += joystick; - - SJoystickInfo returnInfo; - JoystickInfo info; - - info.fd = open(devName.c_str(), O_RDONLY); - if (-1 == info.fd) { - // ...but Ubuntu and possibly other distros - // create the devices in /dev/input - devName = "/dev/input/js"; - devName += joystick; - info.fd = open(devName.c_str(), O_RDONLY); - if (-1 == info.fd) { - // and BSD here - devName = "/dev/joy"; - devName += joystick; - info.fd = open(devName.c_str(), O_RDONLY); - } - } - - if (-1 == info.fd) - continue; - -#ifdef __FreeBSD__ - info.axes = 2; - info.buttons = 2; -#else - ioctl(info.fd, JSIOCGAXES, &(info.axes)); - ioctl(info.fd, JSIOCGBUTTONS, &(info.buttons)); - fcntl(info.fd, F_SETFL, O_NONBLOCK); -#endif - - info.persistentData.EventType = EET_JOYSTICK_INPUT_EVENT; - info.persistentData.JoystickEvent.Joystick = ActiveJoysticks.size(); - - // There's no obvious way to determine which (if any) axes represent a POV - // hat, so we'll just set it to "not used" and forget about it. - info.persistentData.JoystickEvent.POV = 65535; - - ActiveJoysticks.push_back(info); - - returnInfo.Joystick = joystick; - returnInfo.PovHat = SJoystickInfo::POV_HAT_UNKNOWN; - returnInfo.Axes = info.axes; - returnInfo.Buttons = info.buttons; - -#ifndef __FreeBSD__ - char name[80]; - ioctl(info.fd, JSIOCGNAME(80), name); - returnInfo.Name = name; -#endif - - joystickInfo.push_back(returnInfo); - } - - for (joystick = 0; joystick < joystickInfo.size(); ++joystick) { - char logString[256]; - snprintf_irr(logString, sizeof(logString), "Found joystick %d, %d axes, %d buttons '%s'", - joystick, joystickInfo[joystick].Axes, - joystickInfo[joystick].Buttons, joystickInfo[joystick].Name.c_str()); - os::Printer::log(logString, ELL_INFORMATION); - } - - return true; -#else - return false; -#endif // _IRR_COMPILE_WITH_JOYSTICK_EVENTS_ -} - -void CIrrDeviceLinux::pollJoysticks() -{ -#if defined(_IRR_COMPILE_WITH_JOYSTICK_EVENTS_) - if (0 == ActiveJoysticks.size()) - return; - - for (u32 j = 0; j < ActiveJoysticks.size(); ++j) { - JoystickInfo &info = ActiveJoysticks[j]; - -#ifdef __FreeBSD__ - struct joystick js; - if (read(info.fd, &js, sizeof(js)) == sizeof(js)) { - info.persistentData.JoystickEvent.ButtonStates = js.b1 | (js.b2 << 1); /* should be a two-bit field */ - info.persistentData.JoystickEvent.Axis[0] = js.x; /* X axis */ - info.persistentData.JoystickEvent.Axis[1] = js.y; /* Y axis */ - } -#else - struct js_event event; - while (sizeof(event) == read(info.fd, &event, sizeof(event))) { - switch (event.type & ~JS_EVENT_INIT) { - case JS_EVENT_BUTTON: - if (event.value) - info.persistentData.JoystickEvent.ButtonStates |= (1 << event.number); - else - info.persistentData.JoystickEvent.ButtonStates &= ~(1 << event.number); - break; - - case JS_EVENT_AXIS: - if (event.number < SEvent::SJoystickEvent::NUMBER_OF_AXES) - info.persistentData.JoystickEvent.Axis[event.number] = event.value; - break; - - default: - break; - } - } -#endif - - // Send an irrlicht joystick event once per ::run() even if no new data were received. - (void)postEventFromUser(info.persistentData); - } -#endif // _IRR_COMPILE_WITH_JOYSTICK_EVENTS_ -} - -#if defined(_IRR_COMPILE_WITH_X11_) -//! gets text from the clipboard -//! \return Returns 0 if no string is in there, otherwise utf-8 text. -const c8 *CIrrDeviceLinux::getTextFromSelection(Atom selection, core::stringc &text_buffer) const -{ - Window ownerWindow = XGetSelectionOwner(XDisplay, selection); - if (ownerWindow == XWindow) { - return text_buffer.c_str(); - } - - text_buffer = ""; - - if (ownerWindow == None) { - return text_buffer.c_str(); - } - - // delete the property to be set beforehand - XDeleteProperty(XDisplay, XWindow, XA_PRIMARY); - - XConvertSelection(XDisplay, selection, X_ATOM_UTF8_STRING, XA_PRIMARY, - XWindow, CurrentTime); - XFlush(XDisplay); - - // wait for event via a blocking call - XEvent event_ret; - std::pair args(XWindow, selection); - XIfEvent( - XDisplay, &event_ret, [](Display *_display, XEvent *event, XPointer arg) { - auto p = reinterpret_cast *>(arg); - return (Bool)(event->type == SelectionNotify && - event->xselection.requestor == p->first && - event->xselection.selection == p->second && - event->xselection.target == X_ATOM_UTF8_STRING); - }, - (XPointer)&args); - - assert(event_ret.type == SelectionNotify && - event_ret.xselection.requestor == XWindow && - event_ret.xselection.selection == selection && - event_ret.xselection.target == X_ATOM_UTF8_STRING); - - Atom property_set = event_ret.xselection.property; - if (event_ret.xselection.property == None) { - // request failed => empty string - return text_buffer.c_str(); - } - - // check for data - Atom type; - int format; - unsigned long numItems, bytesLeft, dummy; - unsigned char *data = nullptr; - XGetWindowProperty(XDisplay, XWindow, - property_set, // property name - 0, // offset - 0, // length (we only check for data, so 0) - 0, // Delete 0==false - AnyPropertyType, // AnyPropertyType or property identifier - &type, // return type - &format, // return format - &numItems, // number items - &bytesLeft, // remaining bytes for partial reads - &data); // data - if (data) { - XFree(data); - data = nullptr; - } - - // for debugging: - //~ { - //~ char *type_name = XGetAtomName(XDisplay, type); - //~ fprintf(stderr, "CIrrDeviceLinux::getTextFromSelection: actual type: %s (=%ld)\n", - //~ type_name, type); - //~ XFree(type_name); - //~ } - - if (type != X_ATOM_UTF8_STRING && type != X_ATOM_UTF8_MIME_TYPE) { - os::Printer::log("CIrrDeviceLinux::getTextFromSelection: did not get utf-8 string", - ELL_WARNING); - return text_buffer.c_str(); - } - - if (bytesLeft > 0) { - // there is some data to get - int result = XGetWindowProperty(XDisplay, XWindow, property_set, 0, - bytesLeft, 0, AnyPropertyType, &type, &format, - &numItems, &dummy, &data); - if (result == Success) - text_buffer = (c8 *)data; - XFree(data); - } - - // delete the property again, to inform the owner about the successful transfer - XDeleteProperty(XDisplay, XWindow, property_set); - - return text_buffer.c_str(); -} -#endif - -//! gets text from the clipboard -//! \return Returns 0 if no string is in there, otherwise utf-8 text. -const c8 *CIrrDeviceLinux::getTextFromClipboard() const -{ -#if defined(_IRR_COMPILE_WITH_X11_) - return getTextFromSelection(X_ATOM_CLIPBOARD, Clipboard); -#else - return nullptr; -#endif -} - -//! gets text from the primary selection -//! \return Returns 0 if no string is in there, otherwise utf-8 text. -const c8 *CIrrDeviceLinux::getTextFromPrimarySelection() const -{ -#if defined(_IRR_COMPILE_WITH_X11_) - return getTextFromSelection(XA_PRIMARY, PrimarySelection); -#else - return nullptr; -#endif -} - -#if defined(_IRR_COMPILE_WITH_X11_) -bool CIrrDeviceLinux::becomeSelectionOwner(Atom selection) const -{ - XSetSelectionOwner(XDisplay, selection, XWindow, CurrentTime); - XFlush(XDisplay); - Window owner = XGetSelectionOwner(XDisplay, selection); - return owner == XWindow; -} -#endif - -//! copies text to the clipboard -void CIrrDeviceLinux::copyToClipboard(const c8 *text) const -{ -#if defined(_IRR_COMPILE_WITH_X11_) - // Actually there is no clipboard on X but applications just say they own the clipboard and return text when asked. - // Which btw. also means that on X you lose clipboard content when closing applications. - Clipboard = text; - if (!becomeSelectionOwner(X_ATOM_CLIPBOARD)) { - os::Printer::log("CIrrDeviceLinux::copyToClipboard: failed to set owner", ELL_WARNING); - } -#endif -} - -//! copies text to the primary selection -void CIrrDeviceLinux::copyToPrimarySelection(const c8 *text) const -{ -#if defined(_IRR_COMPILE_WITH_X11_) - PrimarySelection = text; - if (!becomeSelectionOwner(XA_PRIMARY)) { - os::Printer::log("CIrrDeviceLinux::copyToPrimarySelection: failed to set owner", ELL_WARNING); - } -#endif -} - -#ifdef _IRR_COMPILE_WITH_X11_ -// return true if the passed event has the type passed in parameter arg -Bool PredicateIsEventType(Display *display, XEvent *event, XPointer arg) -{ - if (event && event->type == *(int *)arg) { - // os::Printer::log("remove event", core::stringc((int)arg).c_str(), ELL_INFORMATION); - return True; - } - return False; -} -#endif //_IRR_COMPILE_WITH_X11_ - -//! Remove all messages pending in the system message loop -void CIrrDeviceLinux::clearSystemMessages() -{ -#ifdef _IRR_COMPILE_WITH_X11_ - if (CreationParams.DriverType != video::EDT_NULL) { - XEvent event; - int usrArg = ButtonPress; - while (XCheckIfEvent(XDisplay, &event, PredicateIsEventType, XPointer(&usrArg)) == True) { - } - usrArg = ButtonRelease; - while (XCheckIfEvent(XDisplay, &event, PredicateIsEventType, XPointer(&usrArg)) == True) { - } - usrArg = MotionNotify; - while (XCheckIfEvent(XDisplay, &event, PredicateIsEventType, XPointer(&usrArg)) == True) { - } - usrArg = KeyRelease; - while (XCheckIfEvent(XDisplay, &event, PredicateIsEventType, XPointer(&usrArg)) == True) { - } - usrArg = KeyPress; - while (XCheckIfEvent(XDisplay, &event, PredicateIsEventType, XPointer(&usrArg)) == True) { - } - } -#endif //_IRR_COMPILE_WITH_X11_ -} - -//! Get the display density in dots per inch. -float CIrrDeviceLinux::getDisplayDensity() const -{ -#ifdef _IRR_COMPILE_WITH_X11_ - if (XDisplay != NULL) { - /* try x direct */ - int dh = DisplayHeight(XDisplay, 0); - int dw = DisplayWidth(XDisplay, 0); - int dh_mm = DisplayHeightMM(XDisplay, 0); - int dw_mm = DisplayWidthMM(XDisplay, 0); - - if (dh_mm != 0 && dw_mm != 0) { - float dpi_height = floor(dh / (dh_mm * 0.039370) + 0.5); - float dpi_width = floor(dw / (dw_mm * 0.039370) + 0.5); - return std::max(dpi_height, dpi_width); - } - } -#endif //_IRR_COMPILE_WITH_X11_ - - return 0.0f; -} - -void CIrrDeviceLinux::initXAtoms() -{ -#ifdef _IRR_COMPILE_WITH_X11_ - X_ATOM_CLIPBOARD = XInternAtom(XDisplay, "CLIPBOARD", False); - X_ATOM_TARGETS = XInternAtom(XDisplay, "TARGETS", False); - X_ATOM_UTF8_STRING = XInternAtom(XDisplay, "UTF8_STRING", False); - X_ATOM_UTF8_MIME_TYPE = XInternAtom(XDisplay, "text/plain;charset=utf-8", False); - X_ATOM_TEXT = XInternAtom(XDisplay, "TEXT", False); - X_ATOM_NETWM_MAXIMIZE_VERT = XInternAtom(XDisplay, "_NET_WM_STATE_MAXIMIZED_VERT", true); - X_ATOM_NETWM_MAXIMIZE_HORZ = XInternAtom(XDisplay, "_NET_WM_STATE_MAXIMIZED_HORZ", true); - X_ATOM_NETWM_STATE = XInternAtom(XDisplay, "_NET_WM_STATE", true); - X_ATOM_NETWM_STATE_FULLSCREEN = XInternAtom(XDisplay, "_NET_WM_STATE_FULLSCREEN", True); -#endif -} - -void CIrrDeviceLinux::initXInput2() -{ -#if defined(_IRR_LINUX_X11_XINPUT2_) - int ev = 0; - int err = 0; - if (!XQueryExtension(XDisplay, "XInputExtension", &XI_EXTENSIONS_OPCODE, &ev, &err)) { - os::Printer::log("X Input extension not available.", ELL_WARNING); - return; - } - - int major = 2; - int minor = 3; - int rc = XIQueryVersion(XDisplay, &major, &minor); - if (rc != Success) { - os::Printer::log("No XI2 support.", ELL_WARNING); - return; - } - - // So far we only use XInput2 for touch events. - // So we enable those and disable all other events for now. - XIEventMask eventMask; - unsigned char mask[XIMaskLen(XI_TouchEnd)]; - memset(mask, 0, sizeof(mask)); - eventMask.deviceid = XIAllMasterDevices; - eventMask.mask_len = sizeof(mask); - eventMask.mask = mask; - XISetMask(eventMask.mask, XI_TouchBegin); - XISetMask(eventMask.mask, XI_TouchUpdate); - XISetMask(eventMask.mask, XI_TouchEnd); - - XISelectEvents(XDisplay, XWindow, &eventMask, 1); -#endif -} - -#ifdef _IRR_COMPILE_WITH_X11_ - -Cursor CIrrDeviceLinux::TextureToMonochromeCursor(video::ITexture *tex, const core::rect &sourceRect, const core::position2d &hotspot) -{ - XImage *sourceImage = XCreateImage(XDisplay, VisualInfo->visual, - 1, // depth, - ZPixmap, // XYBitmap (depth=1), ZPixmap(depth=x) - 0, 0, sourceRect.getWidth(), sourceRect.getHeight(), - 32, // bitmap_pad, - 0 // bytes_per_line (0 means continuous in memory) - ); - sourceImage->data = new char[sourceImage->height * sourceImage->bytes_per_line]; - XImage *maskImage = XCreateImage(XDisplay, VisualInfo->visual, - 1, // depth, - ZPixmap, - 0, 0, sourceRect.getWidth(), sourceRect.getHeight(), - 32, // bitmap_pad, - 0 // bytes_per_line - ); - maskImage->data = new char[maskImage->height * maskImage->bytes_per_line]; - - // write texture into XImage - video::ECOLOR_FORMAT format = tex->getColorFormat(); - u32 bytesPerPixel = video::IImage::getBitsPerPixelFromFormat(format) / 8; - u32 bytesLeftGap = sourceRect.UpperLeftCorner.X * bytesPerPixel; - u32 bytesRightGap = tex->getPitch() - sourceRect.LowerRightCorner.X * bytesPerPixel; - const u8 *data = (const u8 *)tex->lock(video::ETLM_READ_ONLY, 0); - data += sourceRect.UpperLeftCorner.Y * tex->getPitch(); - for (s32 y = 0; y < sourceRect.getHeight(); ++y) { - data += bytesLeftGap; - for (s32 x = 0; x < sourceRect.getWidth(); ++x) { - video::SColor pixelCol; - pixelCol.setData((const void *)data, format); - data += bytesPerPixel; - - if (pixelCol.getAlpha() == 0) { // transparent - XPutPixel(maskImage, x, y, 0); - XPutPixel(sourceImage, x, y, 0); - } else // color - { - if ((pixelCol.getRed() + pixelCol.getGreen() + - pixelCol.getBlue()) / 3 >= 127) - XPutPixel(sourceImage, x, y, 1); - else - XPutPixel(sourceImage, x, y, 0); - XPutPixel(maskImage, x, y, 1); - } - } - data += bytesRightGap; - } - tex->unlock(); - - Pixmap sourcePixmap = XCreatePixmap(XDisplay, XWindow, sourceImage->width, sourceImage->height, sourceImage->depth); - Pixmap maskPixmap = XCreatePixmap(XDisplay, XWindow, maskImage->width, maskImage->height, maskImage->depth); - - XGCValues values; - values.foreground = 1; - values.background = 1; - GC gc = XCreateGC(XDisplay, sourcePixmap, GCForeground | GCBackground, &values); - - XPutImage(XDisplay, sourcePixmap, gc, sourceImage, 0, 0, 0, 0, sourceImage->width, sourceImage->height); - XPutImage(XDisplay, maskPixmap, gc, maskImage, 0, 0, 0, 0, maskImage->width, maskImage->height); - - XFreeGC(XDisplay, gc); - XDestroyImage(sourceImage); - XDestroyImage(maskImage); - - Cursor cursorResult = 0; - XColor foreground, background; - foreground.red = 65535; - foreground.green = 65535; - foreground.blue = 65535; - foreground.flags = DoRed | DoGreen | DoBlue; - background.red = 0; - background.green = 0; - background.blue = 0; - background.flags = DoRed | DoGreen | DoBlue; - - cursorResult = XCreatePixmapCursor(XDisplay, sourcePixmap, maskPixmap, &foreground, &background, hotspot.X, hotspot.Y); - - XFreePixmap(XDisplay, sourcePixmap); - XFreePixmap(XDisplay, maskPixmap); - - return cursorResult; -} - -#ifdef _IRR_LINUX_XCURSOR_ -Cursor CIrrDeviceLinux::TextureToARGBCursor(video::ITexture *tex, const core::rect &sourceRect, const core::position2d &hotspot) -{ - XcursorImage *image = XcursorImageCreate(sourceRect.getWidth(), sourceRect.getHeight()); - image->xhot = hotspot.X; - image->yhot = hotspot.Y; - - // write texture into XcursorImage - video::ECOLOR_FORMAT format = tex->getColorFormat(); - u32 bytesPerPixel = video::IImage::getBitsPerPixelFromFormat(format) / 8; - u32 bytesLeftGap = sourceRect.UpperLeftCorner.X * bytesPerPixel; - u32 bytesRightGap = tex->getPitch() - sourceRect.LowerRightCorner.X * bytesPerPixel; - XcursorPixel *target = image->pixels; - const u8 *data = (const u8 *)tex->lock(video::ETLM_READ_ONLY, 0); - data += sourceRect.UpperLeftCorner.Y * tex->getPitch(); - for (s32 y = 0; y < sourceRect.getHeight(); ++y) { - data += bytesLeftGap; - for (s32 x = 0; x < sourceRect.getWidth(); ++x) { - video::SColor pixelCol; - pixelCol.setData((const void *)data, format); - data += bytesPerPixel; - - *target = (XcursorPixel)pixelCol.color; - ++target; - } - data += bytesRightGap; - } - tex->unlock(); - - Cursor cursorResult = XcursorImageLoadCursor(XDisplay, image); - - XcursorImageDestroy(image); - - return cursorResult; -} -#endif // #ifdef _IRR_LINUX_XCURSOR_ - -Cursor CIrrDeviceLinux::TextureToCursor(video::ITexture *tex, const core::rect &sourceRect, const core::position2d &hotspot) -{ -#ifdef _IRR_LINUX_XCURSOR_ - return TextureToARGBCursor(tex, sourceRect, hotspot); -#else - return TextureToMonochromeCursor(tex, sourceRect, hotspot); -#endif -} -#endif // _IRR_COMPILE_WITH_X11_ - -CIrrDeviceLinux::CCursorControl::CCursorControl(CIrrDeviceLinux *dev, bool null) : - Device(dev) -#ifdef _IRR_COMPILE_WITH_X11_ - , - PlatformBehavior(gui::ECPB_NONE), LastQuery(0) -#ifdef _IRR_LINUX_X11_XINPUT2_ - , - DeviceId(0) -#endif -#endif - , - IsVisible(true), Null(null), UseReferenceRect(false), ActiveIcon(gui::ECI_NORMAL), ActiveIconStartTime(0) -{ -#ifdef _IRR_COMPILE_WITH_X11_ - if (!Null) { -#ifdef _IRR_LINUX_X11_XINPUT2_ - // XIWarpPointer is entirely broken on multi-head setups (see also [1]), - // but behaves better in other cases so we can't just disable it outright. - // [1] https://developer.blender.org/rB165caafb99c6846e53d11c4e966990aaffc06cea - if (XScreenCount(Device->XDisplay) > 1) { - os::Printer::log("Detected classic multi-head setup, not using XIWarpPointer"); - } else { - XIGetClientPointer(Device->XDisplay, Device->XWindow, &DeviceId); - } -#endif - - XGCValues values; - unsigned long valuemask = 0; - - XColor fg, bg; - - // this code, for making the cursor invisible was sent in by - // Sirshane, thank your very much! - - Pixmap invisBitmap = XCreatePixmap(Device->XDisplay, Device->XWindow, 32, 32, 1); - Pixmap maskBitmap = XCreatePixmap(Device->XDisplay, Device->XWindow, 32, 32, 1); - Colormap screen_colormap = DefaultColormap(Device->XDisplay, DefaultScreen(Device->XDisplay)); - XAllocNamedColor(Device->XDisplay, screen_colormap, "black", &fg, &fg); - XAllocNamedColor(Device->XDisplay, screen_colormap, "white", &bg, &bg); - - GC gc = XCreateGC(Device->XDisplay, invisBitmap, valuemask, &values); - - XSetForeground(Device->XDisplay, gc, BlackPixel(Device->XDisplay, DefaultScreen(Device->XDisplay))); - XFillRectangle(Device->XDisplay, invisBitmap, gc, 0, 0, 32, 32); - XFillRectangle(Device->XDisplay, maskBitmap, gc, 0, 0, 32, 32); - - InvisCursor = XCreatePixmapCursor(Device->XDisplay, invisBitmap, maskBitmap, &fg, &bg, 1, 1); - XFreeGC(Device->XDisplay, gc); - XFreePixmap(Device->XDisplay, invisBitmap); - XFreePixmap(Device->XDisplay, maskBitmap); - - initCursors(); - } -#endif -} - -CIrrDeviceLinux::CCursorControl::~CCursorControl() -{ - // Do not clearCursors here as the display is already closed - // TODO (cutealien): dropping cursorcontrol earlier might work, not sure about reason why that's done in stub currently. -} - -#ifdef _IRR_COMPILE_WITH_X11_ -void CIrrDeviceLinux::CCursorControl::clearCursors() -{ - if (!Null) - XFreeCursor(Device->XDisplay, InvisCursor); - for (u32 i = 0; i < Cursors.size(); ++i) { - for (u32 f = 0; f < Cursors[i].Frames.size(); ++f) { - XFreeCursor(Device->XDisplay, Cursors[i].Frames[f].IconHW); - } - } -} - -void CIrrDeviceLinux::CCursorControl::initCursors() -{ - Cursors.push_back(CursorX11(XCreateFontCursor(Device->XDisplay, XC_top_left_arrow))); // (or XC_arrow?) - Cursors.push_back(CursorX11(XCreateFontCursor(Device->XDisplay, XC_crosshair))); - Cursors.push_back(CursorX11(XCreateFontCursor(Device->XDisplay, XC_hand2))); // (or XC_hand1? ) - Cursors.push_back(CursorX11(XCreateFontCursor(Device->XDisplay, XC_question_arrow))); - Cursors.push_back(CursorX11(XCreateFontCursor(Device->XDisplay, XC_xterm))); - Cursors.push_back(CursorX11(XCreateFontCursor(Device->XDisplay, XC_X_cursor))); // (or XC_pirate?) - Cursors.push_back(CursorX11(XCreateFontCursor(Device->XDisplay, XC_watch))); // (or XC_clock?) - Cursors.push_back(CursorX11(XCreateFontCursor(Device->XDisplay, XC_fleur))); - Cursors.push_back(CursorX11(XCreateFontCursor(Device->XDisplay, XC_top_right_corner))); // NESW not available in X11 - Cursors.push_back(CursorX11(XCreateFontCursor(Device->XDisplay, XC_top_left_corner))); // NWSE not available in X11 - Cursors.push_back(CursorX11(XCreateFontCursor(Device->XDisplay, XC_sb_v_double_arrow))); - Cursors.push_back(CursorX11(XCreateFontCursor(Device->XDisplay, XC_sb_h_double_arrow))); - Cursors.push_back(CursorX11(XCreateFontCursor(Device->XDisplay, XC_sb_up_arrow))); // (or XC_center_ptr?) -} - -void CIrrDeviceLinux::CCursorControl::update() -{ - if ((u32)ActiveIcon < Cursors.size() && !Cursors[ActiveIcon].Frames.empty() && Cursors[ActiveIcon].FrameTime) { - // update animated cursors. This could also be done by X11 in case someone wants to figure that out (this way was just easier to implement) - u32 now = Device->getTimer()->getRealTime(); - u32 frame = ((now - ActiveIconStartTime) / Cursors[ActiveIcon].FrameTime) % Cursors[ActiveIcon].Frames.size(); - XDefineCursor(Device->XDisplay, Device->XWindow, Cursors[ActiveIcon].Frames[frame].IconHW); - } -} -#endif - -//! Sets the active cursor icon -void CIrrDeviceLinux::CCursorControl::setActiveIcon(gui::ECURSOR_ICON iconId) -{ -#ifdef _IRR_COMPILE_WITH_X11_ - if (iconId >= (s32)Cursors.size()) - return; - - if (Cursors[iconId].Frames.size()) - XDefineCursor(Device->XDisplay, Device->XWindow, Cursors[iconId].Frames[0].IconHW); - - ActiveIconStartTime = Device->getTimer()->getRealTime(); - ActiveIcon = iconId; -#endif -} - -//! Add a custom sprite as cursor icon. -gui::ECURSOR_ICON CIrrDeviceLinux::CCursorControl::addIcon(const gui::SCursorSprite &icon) -{ -#ifdef _IRR_COMPILE_WITH_X11_ - if (icon.SpriteId >= 0) { - CursorX11 cX11; - cX11.FrameTime = icon.SpriteBank->getSprites()[icon.SpriteId].frameTime; - for (u32 i = 0; i < icon.SpriteBank->getSprites()[icon.SpriteId].Frames.size(); ++i) { - u32 texId = icon.SpriteBank->getSprites()[icon.SpriteId].Frames[i].textureNumber; - u32 rectId = icon.SpriteBank->getSprites()[icon.SpriteId].Frames[i].rectNumber; - core::rect rectIcon = icon.SpriteBank->getPositions()[rectId]; - Cursor cursor = Device->TextureToCursor(icon.SpriteBank->getTexture(texId), rectIcon, icon.HotSpot); - cX11.Frames.push_back(CursorFrameX11(cursor)); - } - - Cursors.push_back(cX11); - - return (gui::ECURSOR_ICON)(Cursors.size() - 1); - } -#endif - return gui::ECI_NORMAL; -} - -//! replace the given cursor icon. -void CIrrDeviceLinux::CCursorControl::changeIcon(gui::ECURSOR_ICON iconId, const gui::SCursorSprite &icon) -{ -#ifdef _IRR_COMPILE_WITH_X11_ - if (iconId >= (s32)Cursors.size()) - return; - - for (u32 i = 0; i < Cursors[iconId].Frames.size(); ++i) - XFreeCursor(Device->XDisplay, Cursors[iconId].Frames[i].IconHW); - - if (icon.SpriteId >= 0) { - CursorX11 cX11; - cX11.FrameTime = icon.SpriteBank->getSprites()[icon.SpriteId].frameTime; - for (u32 i = 0; i < icon.SpriteBank->getSprites()[icon.SpriteId].Frames.size(); ++i) { - u32 texId = icon.SpriteBank->getSprites()[icon.SpriteId].Frames[i].textureNumber; - u32 rectId = icon.SpriteBank->getSprites()[icon.SpriteId].Frames[i].rectNumber; - core::rect rectIcon = icon.SpriteBank->getPositions()[rectId]; - Cursor cursor = Device->TextureToCursor(icon.SpriteBank->getTexture(texId), rectIcon, icon.HotSpot); - cX11.Frames.push_back(CursorFrameX11(cursor)); - } - - Cursors[iconId] = cX11; - } -#endif -} - -core::dimension2di CIrrDeviceLinux::CCursorControl::getSupportedIconSize() const -{ - // this returns the closest match that is smaller or same size, so we just pass a value which should be large enough for cursors - unsigned int width = 0, height = 0; -#ifdef _IRR_COMPILE_WITH_X11_ - XQueryBestCursor(Device->XDisplay, Device->XWindow, 64, 64, &width, &height); -#endif - return core::dimension2di(width, height); -} - -#endif // _IRR_COMPILE_WITH_X11_DEVICE_ diff --git a/irr/src/CIrrDeviceLinux.h b/irr/src/CIrrDeviceLinux.h deleted file mode 100644 index a5a217cc8b..0000000000 --- a/irr/src/CIrrDeviceLinux.h +++ /dev/null @@ -1,471 +0,0 @@ -// Copyright (C) 2002-2012 Nikolaus Gebhardt -// This file is part of the "Irrlicht Engine". -// For conditions of distribution and use, see copyright notice in irrlicht.h - -#pragma once - -#ifdef _IRR_COMPILE_WITH_X11_DEVICE_ - -#include "CIrrDeviceStub.h" -#include "IrrlichtDevice.h" -#include "ICursorControl.h" -#include "os.h" -namespace video -{ - class ITexture; -} - -#ifdef _IRR_COMPILE_WITH_X11_ - -#include -#include -#include -#include - -#ifdef _IRR_LINUX_X11_XINPUT2_ -#include -#endif - -#else -#define KeySym s32 -#endif - -class CIrrDeviceLinux : public CIrrDeviceStub -{ -public: - //! constructor - CIrrDeviceLinux(const SIrrlichtCreationParameters ¶m); - - //! destructor - virtual ~CIrrDeviceLinux(); - - //! runs the device. Returns false if device wants to be deleted - bool run() override; - - //! Cause the device to temporarily pause execution and let other processes to run - // This should bring down processor usage without major performance loss for Irrlicht - void yield() override; - - //! Pause execution and let other processes to run for a specified amount of time. - void sleep(u32 timeMs, bool pauseTimer) override; - - //! sets the caption of the window - void setWindowCaption(const wchar_t *text) override; - - //! Sets the window icon. - bool setWindowIcon(const video::IImage *img) override; - - //! returns if window is active. if not, nothing need to be drawn - bool isWindowActive() const override; - - //! returns if window has focus. - bool isWindowFocused() const override; - - //! returns if window is minimized. - bool isWindowMinimized() const override; - - //! returns last state from maximizeWindow() and restoreWindow() - bool isWindowMaximized() const override; - - //! Checks if the Irrlicht device supports touch events. - bool supportsTouchEvents() const override; - - //! returns color format of the window. - video::ECOLOR_FORMAT getColorFormat() const override; - - //! notifies the device that it should close itself - void closeDevice() override; - - //! Sets if the window should be resizable in windowed mode. - void setResizable(bool resize = false) override; - - //! Resize the render window. - void setWindowSize(const core::dimension2d &size) override; - - //! Minimizes the window. - void minimizeWindow() override; - - //! Maximizes the window. - void maximizeWindow() override; - - //! Restores the window size. - void restoreWindow() override; - - //! Get the position of this window on screen - core::position2di getWindowPosition() override; - - //! Activate any joysticks, and generate events for them. - bool activateJoysticks(core::array &joystickInfo) override; - - //! gets text from the clipboard - //! \return Returns 0 if no string is in there, otherwise utf-8 text. - virtual const c8 *getTextFromClipboard() const; - - //! gets text from the primary selection - //! \return Returns 0 if no string is in there, otherwise utf-8 text. - virtual const c8 *getTextFromPrimarySelection() const; - - //! copies text to the clipboard - //! This sets the clipboard selection and _not_ the primary selection. - //! @param text The text in utf-8 - virtual void copyToClipboard(const c8 *text) const; - - //! copies text to the primary selection - //! This sets the primary selection which you have on X on the middle mouse button. - //! @param text The text in utf-8 - virtual void copyToPrimarySelection(const c8 *text) const; - - //! Remove all messages pending in the system message loop - void clearSystemMessages() override; - - //! Get the device type - E_DEVICE_TYPE getType() const override - { - return EIDT_X11; - } - - //! Get the display density in dots per inch. - float getDisplayDensity() const override; - -#ifdef _IRR_COMPILE_WITH_X11_ - // convert an Irrlicht texture to a X11 cursor - Cursor TextureToCursor(video::ITexture *tex, const core::rect &sourceRect, const core::position2d &hotspot); - Cursor TextureToMonochromeCursor(video::ITexture *tex, const core::rect &sourceRect, const core::position2d &hotspot); -#ifdef _IRR_LINUX_XCURSOR_ - Cursor TextureToARGBCursor(video::ITexture *tex, const core::rect &sourceRect, const core::position2d &hotspot); -#endif -#endif - -private: - //! create the driver - void createDriver(); - - bool createWindow(); - - void createKeyMap(); - - void pollJoysticks(); - - void initXAtoms(); - - void initXInput2(); - - bool switchToFullscreen(); - - void setupTopLevelXorgWindow(); - -#ifdef _IRR_COMPILE_WITH_X11_ - bool createInputContext(); - void destroyInputContext(); - EKEY_CODE getKeyCode(XEvent &event); - - const c8 *getTextFromSelection(Atom selection, core::stringc &text_buffer) const; - bool becomeSelectionOwner(Atom selection) const; -#endif - - //! Implementation of the linux cursor control - class CCursorControl : public gui::ICursorControl - { - public: - CCursorControl(CIrrDeviceLinux *dev, bool null); - - ~CCursorControl(); - - //! Changes the visible state of the mouse cursor. - void setVisible(bool visible) override - { - if (visible == IsVisible) - return; - IsVisible = visible; -#ifdef _IRR_COMPILE_WITH_X11_ - if (!Null) { - if (!IsVisible) - XDefineCursor(Device->XDisplay, Device->XWindow, InvisCursor); - else - XUndefineCursor(Device->XDisplay, Device->XWindow); - } -#endif - } - - //! Returns if the cursor is currently visible. - bool isVisible() const override - { - return IsVisible; - } - - //! Sets the new position of the cursor. - void setPosition(const core::position2d &pos) override - { - setPosition(pos.X, pos.Y); - } - - //! Sets the new position of the cursor. - void setPosition(f32 x, f32 y) override - { - setPosition((s32)(x * Device->Width), (s32)(y * Device->Height)); - } - - //! Sets the new position of the cursor. - void setPosition(const core::position2d &pos) override - { - setPosition(pos.X, pos.Y); - } - - //! Sets the new position of the cursor. - void setPosition(s32 x, s32 y) override - { -#ifdef _IRR_COMPILE_WITH_X11_ - - if (!Null) { - if (UseReferenceRect) { -// NOTE: XIWarpPointer works when X11 has set a coordinate transformation matrix for the mouse unlike XWarpPointer -// which runs into a bug mentioned here: https://gitlab.freedesktop.org/xorg/xserver/-/issues/600 -// So also workaround for Irrlicht bug #450 -#ifdef _IRR_LINUX_X11_XINPUT2_ - if (DeviceId != 0) { - XIWarpPointer(Device->XDisplay, - DeviceId, - None, - Device->XWindow, 0, 0, - Device->Width, - Device->Height, - ReferenceRect.UpperLeftCorner.X + x, - ReferenceRect.UpperLeftCorner.Y + y); - } else -#endif - { - XWarpPointer(Device->XDisplay, - None, - Device->XWindow, 0, 0, - Device->Width, - Device->Height, - ReferenceRect.UpperLeftCorner.X + x, - ReferenceRect.UpperLeftCorner.Y + y); - } - } else { -#ifdef _IRR_LINUX_X11_XINPUT2_ - if (DeviceId != 0) { - XIWarpPointer(Device->XDisplay, - DeviceId, - None, - Device->XWindow, 0, 0, - Device->Width, - Device->Height, x, y); - } else -#endif - { - XWarpPointer(Device->XDisplay, - None, - Device->XWindow, 0, 0, - Device->Width, - Device->Height, x, y); - } - } - XFlush(Device->XDisplay); - } -#endif - CursorPos.X = x; - CursorPos.Y = y; - } - - //! Returns the current position of the mouse cursor. - const core::position2d &getPosition(bool updateCursor) override - { - if (updateCursor) - updateCursorPos(); - return CursorPos; - } - - //! Returns the current position of the mouse cursor. - core::position2d getRelativePosition(bool updateCursor) override - { - if (updateCursor) - updateCursorPos(); - - if (!UseReferenceRect) { - return core::position2d(CursorPos.X / (f32)Device->Width, - CursorPos.Y / (f32)Device->Height); - } - - return core::position2d(CursorPos.X / (f32)ReferenceRect.getWidth(), - CursorPos.Y / (f32)ReferenceRect.getHeight()); - } - - void setReferenceRect(core::rect *rect = 0) override - { - if (rect) { - ReferenceRect = *rect; - UseReferenceRect = true; - - // prevent division through zero and uneven sizes - - if (!ReferenceRect.getHeight() || ReferenceRect.getHeight() % 2) - ReferenceRect.LowerRightCorner.Y += 1; - - if (!ReferenceRect.getWidth() || ReferenceRect.getWidth() % 2) - ReferenceRect.LowerRightCorner.X += 1; - } else - UseReferenceRect = false; - } - - //! Sets the active cursor icon - void setActiveIcon(gui::ECURSOR_ICON iconId) override; - - //! Gets the currently active icon - gui::ECURSOR_ICON getActiveIcon() const override - { - return ActiveIcon; - } - - //! Add a custom sprite as cursor icon. - gui::ECURSOR_ICON addIcon(const gui::SCursorSprite &icon) override; - - //! replace the given cursor icon. - void changeIcon(gui::ECURSOR_ICON iconId, const gui::SCursorSprite &icon) override; - - //! Return a system-specific size which is supported for cursors. Larger icons will fail, smaller icons might work. - core::dimension2di getSupportedIconSize() const override; - -#ifdef _IRR_COMPILE_WITH_X11_ - //! Set platform specific behavior flags. - void setPlatformBehavior(gui::ECURSOR_PLATFORM_BEHAVIOR behavior) override { PlatformBehavior = behavior; } - - //! Return platform specific behavior. - gui::ECURSOR_PLATFORM_BEHAVIOR getPlatformBehavior() const override { return PlatformBehavior; } - - void update(); - void clearCursors(); -#endif - private: - void updateCursorPos() - { -#ifdef _IRR_COMPILE_WITH_X11_ - if (Null) - return; - - if (PlatformBehavior & gui::ECPB_X11_CACHE_UPDATES && !os::Timer::isStopped()) { - u32 now = os::Timer::getTime(); - if (now <= LastQuery) - return; - LastQuery = now; - } - - Window tmp; - int itmp1, itmp2; - unsigned int maskreturn; - XQueryPointer(Device->XDisplay, Device->XWindow, - &tmp, &tmp, - &itmp1, &itmp2, - &CursorPos.X, &CursorPos.Y, &maskreturn); -#endif - } - - CIrrDeviceLinux *Device; - core::position2d CursorPos; - core::rect ReferenceRect; -#ifdef _IRR_COMPILE_WITH_X11_ - gui::ECURSOR_PLATFORM_BEHAVIOR PlatformBehavior; - u32 LastQuery; - Cursor InvisCursor; - -#ifdef _IRR_LINUX_X11_XINPUT2_ - int DeviceId; -#endif - - struct CursorFrameX11 - { - CursorFrameX11() : - IconHW(0) {} - CursorFrameX11(Cursor icon) : - IconHW(icon) {} - - Cursor IconHW; // hardware cursor - }; - - struct CursorX11 - { - CursorX11() {} - explicit CursorX11(Cursor iconHw, u32 frameTime = 0) : - FrameTime(frameTime) - { - Frames.push_back(CursorFrameX11(iconHw)); - } - core::array Frames; - u32 FrameTime; - }; - - core::array Cursors; - - void initCursors(); -#endif - bool IsVisible; - bool Null; - bool UseReferenceRect; - gui::ECURSOR_ICON ActiveIcon; - u32 ActiveIconStartTime; - }; - - friend class CCursorControl; - -#ifdef _IRR_COMPILE_WITH_X11_ - friend class COpenGLDriver; - - Display *XDisplay; - XVisualInfo *VisualInfo; - int Screennr; - Window XWindow; - XSetWindowAttributes WndAttributes; - XSizeHints *StdHints; - XIM XInputMethod; - XIC XInputContext; - bool HasNetWM; - // text is utf-8 - mutable core::stringc Clipboard; - mutable core::stringc PrimarySelection; -#endif -#if defined(_IRR_LINUX_X11_XINPUT2_) - int currentTouchedCount; -#endif - u32 Width, Height; - bool WindowHasFocus; - bool WindowMinimized; - bool WindowMaximized; - bool ExternalWindow; - int AutorepeatSupport; - - struct SKeyMap - { - SKeyMap() {} - SKeyMap(s32 x11, s32 win32) : - X11Key(x11), Win32Key(win32) - { - } - - KeySym X11Key; - s32 Win32Key; - - bool operator<(const SKeyMap &o) const - { - return X11Key < o.X11Key; - } - }; - - core::array KeyMap; - -#if defined(_IRR_COMPILE_WITH_JOYSTICK_EVENTS_) - struct JoystickInfo - { - int fd; - int axes; - int buttons; - - SEvent persistentData; - - JoystickInfo() : - fd(-1), axes(0), buttons(0) {} - }; - core::array ActiveJoysticks; -#endif -}; - -#endif // _IRR_COMPILE_WITH_X11_DEVICE_ diff --git a/irr/src/CIrrDeviceOSX.h b/irr/src/CIrrDeviceOSX.h deleted file mode 100644 index 8e338a9cb3..0000000000 --- a/irr/src/CIrrDeviceOSX.h +++ /dev/null @@ -1,231 +0,0 @@ -// Copyright (C) 2005-2006 Etienne Petitjean -// Copyright (C) 2007-2012 Christian Stehno -// This file is part of the "Irrlicht Engine". -// For conditions of distribution and use, see copyright notice in Irrlicht.h - -#pragma once - -#ifdef _IRR_COMPILE_WITH_OSX_DEVICE_ - -#include "CIrrDeviceStub.h" -#include "IrrlichtDevice.h" -#include "IGUIEnvironment.h" -#include "ICursorControl.h" - -#import -#import - -#include - -class CIrrDeviceMacOSX; - -@interface CIrrDelegateOSX : NSObject - -- (id)initWithDevice:(CIrrDeviceMacOSX *)device; -- (void)terminate:(id)sender; -- (BOOL)isQuit; - -@end - -class CIrrDeviceMacOSX : public CIrrDeviceStub -{ -public: - //! constructor - CIrrDeviceMacOSX(const SIrrlichtCreationParameters ¶ms); - - //! destructor - virtual ~CIrrDeviceMacOSX(); - - //! runs the device. Returns false if device wants to be deleted - bool run() override; - - //! Cause the device to temporarily pause execution and let other processes to run - // This should bring down processor usage without major performance loss for Irrlicht - void yield() override; - - //! Pause execution and let other processes to run for a specified amount of time. - void sleep(u32 timeMs, bool pauseTimer) override; - - //! sets the caption of the window - void setWindowCaption(const wchar_t *text) override; - - //! returns if window is active. if not, nothing need to be drawn - bool isWindowActive() const override; - - //! Checks if the Irrlicht window has focus - bool isWindowFocused() const override; - - //! Checks if the Irrlicht window is minimized - bool isWindowMinimized() const override; - - //! notifies the device that it should close itself - void closeDevice() override; - - //! Sets if the window should be resizable in windowed mode. - void setResizable(bool resize) override; - - //! Returns true if the window is resizable, false if not - virtual bool isResizable() const; - - //! Minimizes the window if possible - void minimizeWindow() override; - - //! Maximizes the window if possible. - void maximizeWindow() override; - - //! Restore the window to normal size if possible. - void restoreWindow() override; - - //! Get the position of this window on screen - core::position2di getWindowPosition() override; - - //! Activate any joysticks, and generate events for them. - bool activateJoysticks(core::array &joystickInfo) override; - - //! Get the device type - E_DEVICE_TYPE getType() const override - { - return EIDT_OSX; - } - - void setMouseLocation(int x, int y); - void setResize(int width, int height); - void setCursorVisible(bool visible); - void setWindow(NSWindow *window); - -private: - //! create the driver - void createDriver(); - - //! Implementation of the macos x cursor control - class CCursorControl : public gui::ICursorControl - { - public: - CCursorControl(const core::dimension2d &wsize, CIrrDeviceMacOSX *device) : - WindowSize(wsize), InvWindowSize(0.0f, 0.0f), Device(device), IsVisible(true), UseReferenceRect(false) - { - CursorPos.X = CursorPos.Y = 0; - if (WindowSize.Width != 0) - InvWindowSize.Width = 1.0f / WindowSize.Width; - if (WindowSize.Height != 0) - InvWindowSize.Height = 1.0f / WindowSize.Height; - } - - //! Changes the visible state of the mouse cursor. - void setVisible(bool visible) override - { - IsVisible = visible; - Device->setCursorVisible(visible); - } - - //! Returns if the cursor is currently visible. - bool isVisible() const override - { - return IsVisible; - } - - //! Sets the new position of the cursor. - void setPosition(const core::position2d &pos) override - { - setPosition(pos.X, pos.Y); - } - - //! Sets the new position of the cursor. - void setPosition(f32 x, f32 y) override - { - setPosition((s32)(x * WindowSize.Width), (s32)(y * WindowSize.Height)); - } - - //! Sets the new position of the cursor. - void setPosition(const core::position2d &pos) override - { - if (CursorPos.X != pos.X || CursorPos.Y != pos.Y) - setPosition(pos.X, pos.Y); - } - - //! Sets the new position of the cursor. - void setPosition(s32 x, s32 y) override - { - if (UseReferenceRect) { - Device->setMouseLocation(ReferenceRect.UpperLeftCorner.X + x, ReferenceRect.UpperLeftCorner.Y + y); - } else { - Device->setMouseLocation(x, y); - } - } - - //! Returns the current position of the mouse cursor. - const core::position2d &getPosition(bool updateCursor) override - { - return CursorPos; - } - - //! Returns the current position of the mouse cursor. - core::position2d getRelativePosition(bool updateCursor) override - { - if (!UseReferenceRect) { - return core::position2d(CursorPos.X * InvWindowSize.Width, - CursorPos.Y * InvWindowSize.Height); - } - - return core::position2d(CursorPos.X / (f32)ReferenceRect.getWidth(), - CursorPos.Y / (f32)ReferenceRect.getHeight()); - } - - //! Sets an absolute reference rect for calculating the cursor position. - void setReferenceRect(core::rect *rect = 0) override - { - if (rect) { - ReferenceRect = *rect; - UseReferenceRect = true; - - // prevent division through zero and uneven sizes - - if (!ReferenceRect.getHeight() || ReferenceRect.getHeight() % 2) - ReferenceRect.LowerRightCorner.Y += 1; - - if (!ReferenceRect.getWidth() || ReferenceRect.getWidth() % 2) - ReferenceRect.LowerRightCorner.X += 1; - } else - UseReferenceRect = false; - } - - //! Updates the internal cursor position - void updateInternalCursorPosition(int x, int y) - { - CursorPos.X = x; - CursorPos.Y = y; - } - - private: - core::position2d CursorPos; - core::dimension2d WindowSize; - core::dimension2d InvWindowSize; - core::rect ReferenceRect; - CIrrDeviceMacOSX *Device; - bool IsVisible; - bool UseReferenceRect; - }; - - bool createWindow(); - void initKeycodes(); - void storeMouseLocation(); - void postMouseEvent(void *event, SEvent &ievent); - void postKeyEvent(void *event, SEvent &ievent, bool pressed); - void pollJoysticks(); - - NSWindow *Window; - CGDirectDisplayID Display; - std::map KeyCodes; - int DeviceWidth; - int DeviceHeight; - int ScreenWidth; - int ScreenHeight; - u32 MouseButtonStates; - bool IsFullscreen; - bool IsActive; - bool IsShiftDown; - bool IsControlDown; - bool IsResizable; -}; - -#endif // _IRR_COMPILE_WITH_OSX_DEVICE_ diff --git a/irr/src/CIrrDeviceOSX.mm b/irr/src/CIrrDeviceOSX.mm deleted file mode 100644 index 7ee791b40f..0000000000 --- a/irr/src/CIrrDeviceOSX.mm +++ /dev/null @@ -1,1457 +0,0 @@ -// Copyright (C) 2005-2006 Etienne Petitjean -// Copyright (C) 2007-2012 Christian Stehno -// Copyright (C) 2013-2015 Patryk Nadrowski -// This file is part of the "Irrlicht Engine". -// For conditions of distribution and use, see copyright notice in Irrlicht.h - -#ifdef _IRR_COMPILE_WITH_OSX_DEVICE_ - -#import -#import - -#include "CIrrDeviceOSX.h" - -#include "IEventReceiver.h" -#include "IVideoDriver.h" -#include "os.h" -#include "CTimer.h" -#include "irrString.h" -#include "Keycodes.h" -#include -#include -#include "COSOperator.h" -#include "CColorConverter.h" -#include "irrlicht.h" -#include - -#include -#include - -#include "CNSOGLManager.h" - -#if defined _IRR_COMPILE_WITH_JOYSTICK_EVENTS_ - -#include -#include -#include -#include -#include - -struct JoystickComponent -{ - IOHIDElementCookie cookie; // unique value which identifies element, will NOT change - long min; // reported min value possible - long max; // reported max value possible - - long minRead; // min read value - long maxRead; // max read value - - JoystickComponent() : - min(0), minRead(0), max(0), maxRead(0) - { - } -}; - -struct JoystickInfo -{ - core::array axisComp; - core::array buttonComp; - core::array hatComp; - - int hats; - int axes; - int buttons; - int numActiveJoysticks; - - SEvent persistentData; - - IOHIDDeviceInterface **interface; - bool removed; - char joystickName[256]; - long usage; // usage page from IOUSBHID Parser.h which defines general usage - long usagePage; // usage within above page from IOUSBHID Parser.h which defines specific usage - - JoystickInfo() : - hats(0), axes(0), buttons(0), interface(0), removed(false), usage(0), usagePage(0), numActiveJoysticks(0) - { - interface = NULL; - memset(joystickName, '\0', 256); - axisComp.clear(); - buttonComp.clear(); - hatComp.clear(); - - persistentData.EventType = EET_JOYSTICK_INPUT_EVENT; - persistentData.JoystickEvent.POV = 65535; - persistentData.JoystickEvent.ButtonStates = 0; - } -}; -core::array ActiveJoysticks; - -// helper functions for init joystick -static IOReturn closeJoystickDevice(JoystickInfo *joyInfo) -{ - IOReturn result = kIOReturnSuccess; - if (joyInfo && joyInfo->interface) { - /* close the interface */ - result = (*(joyInfo->interface))->close(joyInfo->interface); - if (kIOReturnNotOpen == result) { - /* do nothing as device was not opened, thus can't be closed */ - } else if (kIOReturnSuccess != result) - os::Printer::log("IOHIDDeviceInterface failed to close", ELL_ERROR); - /* release the interface */ - result = (*(joyInfo->interface))->Release(joyInfo->interface); - if (kIOReturnSuccess != result) - os::Printer::log("IOHIDDeviceInterface failed to release", ELL_ERROR); - joyInfo->interface = NULL; - } - return result; -} - -static void addComponentInfo(CFTypeRef refElement, JoystickComponent *pComponent, int numActiveJoysticks) -{ - long number; - CFTypeRef refType; - - refType = CFDictionaryGetValue((CFDictionaryRef)refElement, CFSTR(kIOHIDElementCookieKey)); - if (refType && CFNumberGetValue((CFNumberRef)refType, kCFNumberLongType, &number)) - pComponent->cookie = (IOHIDElementCookie)number; - refType = CFDictionaryGetValue((CFDictionaryRef)refElement, CFSTR(kIOHIDElementMinKey)); - if (refType && CFNumberGetValue((CFNumberRef)refType, kCFNumberLongType, &number)) - pComponent->minRead = pComponent->min = number; - refType = CFDictionaryGetValue((CFDictionaryRef)refElement, CFSTR(kIOHIDElementMaxKey)); - if (refType && CFNumberGetValue((CFNumberRef)refType, kCFNumberLongType, &number)) - pComponent->maxRead = pComponent->max = number; -} - -static void getJoystickComponentArrayHandler(const void *value, void *parameter); - -static void addJoystickComponent(CFTypeRef refElement, JoystickInfo *joyInfo) -{ - long elementType, usagePage, usage; - CFTypeRef refElementType = CFDictionaryGetValue((CFDictionaryRef)refElement, CFSTR(kIOHIDElementTypeKey)); - CFTypeRef refUsagePage = CFDictionaryGetValue((CFDictionaryRef)refElement, CFSTR(kIOHIDElementUsagePageKey)); - CFTypeRef refUsage = CFDictionaryGetValue((CFDictionaryRef)refElement, CFSTR(kIOHIDElementUsageKey)); - - if ((refElementType) && (CFNumberGetValue((CFNumberRef)refElementType, kCFNumberLongType, &elementType))) { - /* look at types of interest */ - if ((elementType == kIOHIDElementTypeInput_Misc) || (elementType == kIOHIDElementTypeInput_Button) || - (elementType == kIOHIDElementTypeInput_Axis)) { - if (refUsagePage && CFNumberGetValue((CFNumberRef)refUsagePage, kCFNumberLongType, &usagePage) && - refUsage && CFNumberGetValue((CFNumberRef)refUsage, kCFNumberLongType, &usage)) { - switch (usagePage) /* only interested in kHIDPage_GenericDesktop and kHIDPage_Button */ - { - case kHIDPage_GenericDesktop: { - switch (usage) /* look at usage to determine function */ - { - case kHIDUsage_GD_X: - case kHIDUsage_GD_Y: - case kHIDUsage_GD_Z: - case kHIDUsage_GD_Rx: - case kHIDUsage_GD_Ry: - case kHIDUsage_GD_Rz: - case kHIDUsage_GD_Slider: - case kHIDUsage_GD_Dial: - case kHIDUsage_GD_Wheel: { - joyInfo->axes++; - JoystickComponent newComponent; - addComponentInfo(refElement, &newComponent, joyInfo->numActiveJoysticks); - joyInfo->axisComp.push_back(newComponent); - } break; - case kHIDUsage_GD_Hatswitch: { - joyInfo->hats++; - JoystickComponent newComponent; - addComponentInfo(refElement, &newComponent, joyInfo->numActiveJoysticks); - joyInfo->hatComp.push_back(newComponent); - } break; - } - } break; - case kHIDPage_Button: { - joyInfo->buttons++; - JoystickComponent newComponent; - addComponentInfo(refElement, &newComponent, joyInfo->numActiveJoysticks); - joyInfo->buttonComp.push_back(newComponent); - } break; - default: - break; - } - } - } else if (kIOHIDElementTypeCollection == elementType) { - // get elements - CFTypeRef refElementTop = CFDictionaryGetValue((CFMutableDictionaryRef)refElement, CFSTR(kIOHIDElementKey)); - if (refElementTop) { - CFTypeID type = CFGetTypeID(refElementTop); - if (type == CFArrayGetTypeID()) { - CFRange range = {0, CFArrayGetCount((CFArrayRef)refElementTop)}; - CFArrayApplyFunction((CFArrayRef)refElementTop, range, getJoystickComponentArrayHandler, joyInfo); - } - } - } - } -} - -static void getJoystickComponentArrayHandler(const void *value, void *parameter) -{ - if (CFGetTypeID(value) == CFDictionaryGetTypeID()) - addJoystickComponent((CFTypeRef)value, (JoystickInfo *)parameter); -} - -static void joystickTopLevelElementHandler(const void *value, void *parameter) -{ - CFTypeRef refCF = 0; - if (CFGetTypeID(value) != CFDictionaryGetTypeID()) - return; - refCF = CFDictionaryGetValue((CFDictionaryRef)value, CFSTR(kIOHIDElementUsagePageKey)); - if (!CFNumberGetValue((CFNumberRef)refCF, kCFNumberLongType, &((JoystickInfo *)parameter)->usagePage)) - os::Printer::log("CFNumberGetValue error retrieving JoystickInfo->usagePage", ELL_ERROR); - refCF = CFDictionaryGetValue((CFDictionaryRef)value, CFSTR(kIOHIDElementUsageKey)); - if (!CFNumberGetValue((CFNumberRef)refCF, kCFNumberLongType, &((JoystickInfo *)parameter)->usage)) - os::Printer::log("CFNumberGetValue error retrieving JoystickInfo->usage", ELL_ERROR); -} - -static void getJoystickDeviceInfo(io_object_t hidDevice, CFMutableDictionaryRef hidProperties, JoystickInfo *joyInfo) -{ - CFMutableDictionaryRef usbProperties = 0; - io_registry_entry_t parent1, parent2; - - /* Mac OS X currently is not mirroring all USB properties to HID page so need to look at USB device page also - * get dictionary for usb properties: step up two levels and get CF dictionary for USB properties - */ - if ((KERN_SUCCESS == IORegistryEntryGetParentEntry(hidDevice, kIOServicePlane, &parent1)) && - (KERN_SUCCESS == IORegistryEntryGetParentEntry(parent1, kIOServicePlane, &parent2)) && - (KERN_SUCCESS == IORegistryEntryCreateCFProperties(parent2, &usbProperties, kCFAllocatorDefault, kNilOptions))) { - if (usbProperties) { - CFTypeRef refCF = 0; - /* get device info - * try hid dictionary first, if fail then go to usb dictionary - */ - - /* get joystickName name */ - refCF = CFDictionaryGetValue(hidProperties, CFSTR(kIOHIDProductKey)); - if (!refCF) - refCF = CFDictionaryGetValue(usbProperties, CFSTR("USB Product Name")); - if (refCF) { - if (!CFStringGetCString((CFStringRef)refCF, joyInfo->joystickName, 256, CFStringGetSystemEncoding())) - os::Printer::log("CFStringGetCString error getting joyInfo->joystickName", ELL_ERROR); - } - - /* get usage page and usage */ - refCF = CFDictionaryGetValue(hidProperties, CFSTR(kIOHIDPrimaryUsagePageKey)); - if (refCF) { - if (!CFNumberGetValue((CFNumberRef)refCF, kCFNumberLongType, &joyInfo->usagePage)) - os::Printer::log("CFNumberGetValue error getting joyInfo->usagePage", ELL_ERROR); - refCF = CFDictionaryGetValue(hidProperties, CFSTR(kIOHIDPrimaryUsageKey)); - if (refCF) - if (!CFNumberGetValue((CFNumberRef)refCF, kCFNumberLongType, &joyInfo->usage)) - os::Printer::log("CFNumberGetValue error getting joyInfo->usage", ELL_ERROR); - } - - if (NULL == refCF) /* get top level element HID usage page or usage */ - { - /* use top level element instead */ - CFTypeRef refCFTopElement = 0; - refCFTopElement = CFDictionaryGetValue(hidProperties, CFSTR(kIOHIDElementKey)); - { - /* refCFTopElement points to an array of element dictionaries */ - CFRange range = {0, CFArrayGetCount((CFArrayRef)refCFTopElement)}; - CFArrayApplyFunction((CFArrayRef)refCFTopElement, range, joystickTopLevelElementHandler, joyInfo); - } - } - - CFRelease(usbProperties); - } else - os::Printer::log("IORegistryEntryCreateCFProperties failed to create usbProperties", ELL_ERROR); - - if (kIOReturnSuccess != IOObjectRelease(parent2)) - os::Printer::log("IOObjectRelease failed to release parent2", ELL_ERROR); - if (kIOReturnSuccess != IOObjectRelease(parent1)) - os::Printer::log("IOObjectRelease failed to release parent1", ELL_ERROR); - } -} - -#endif // _IRR_COMPILE_WITH_JOYSTICK_EVENTS_ - -// Contents from Events.h from Carbon/HIToolbox but we need it with Cocoa too -// and for some reason no Cocoa equivalent of these constants seems provided. -// So I'm doing like everyone else and using copy-and-paste. - -/* - * Summary: - * Virtual keycodes - * - * Discussion: - * These constants are the virtual keycodes defined originally in - * Inside Mac Volume V, pg. V-191. They identify physical keys on a - * keyboard. Those constants with "ANSI" in the name are labeled - * according to the key position on an ANSI-standard US keyboard. - * For example, kVK_ANSI_A indicates the virtual keycode for the key - * with the letter 'A' in the US keyboard layout. Other keyboard - * layouts may have the 'A' key label on a different physical key; - * in this case, pressing 'A' will generate a different virtual - * keycode. - */ -enum -{ - kVK_ANSI_A = 0x00, - kVK_ANSI_S = 0x01, - kVK_ANSI_D = 0x02, - kVK_ANSI_F = 0x03, - kVK_ANSI_H = 0x04, - kVK_ANSI_G = 0x05, - kVK_ANSI_Z = 0x06, - kVK_ANSI_X = 0x07, - kVK_ANSI_C = 0x08, - kVK_ANSI_V = 0x09, - kVK_ANSI_B = 0x0B, - kVK_ANSI_Q = 0x0C, - kVK_ANSI_W = 0x0D, - kVK_ANSI_E = 0x0E, - kVK_ANSI_R = 0x0F, - kVK_ANSI_Y = 0x10, - kVK_ANSI_T = 0x11, - kVK_ANSI_1 = 0x12, - kVK_ANSI_2 = 0x13, - kVK_ANSI_3 = 0x14, - kVK_ANSI_4 = 0x15, - kVK_ANSI_6 = 0x16, - kVK_ANSI_5 = 0x17, - kVK_ANSI_Equal = 0x18, - kVK_ANSI_9 = 0x19, - kVK_ANSI_7 = 0x1A, - kVK_ANSI_Minus = 0x1B, - kVK_ANSI_8 = 0x1C, - kVK_ANSI_0 = 0x1D, - kVK_ANSI_RightBracket = 0x1E, - kVK_ANSI_O = 0x1F, - kVK_ANSI_U = 0x20, - kVK_ANSI_LeftBracket = 0x21, - kVK_ANSI_I = 0x22, - kVK_ANSI_P = 0x23, - kVK_ANSI_L = 0x25, - kVK_ANSI_J = 0x26, - kVK_ANSI_Quote = 0x27, - kVK_ANSI_K = 0x28, - kVK_ANSI_Semicolon = 0x29, - kVK_ANSI_Backslash = 0x2A, - kVK_ANSI_Comma = 0x2B, - kVK_ANSI_Slash = 0x2C, - kVK_ANSI_N = 0x2D, - kVK_ANSI_M = 0x2E, - kVK_ANSI_Period = 0x2F, - kVK_ANSI_Grave = 0x32, - kVK_ANSI_KeypadDecimal = 0x41, - kVK_ANSI_KeypadMultiply = 0x43, - kVK_ANSI_KeypadPlus = 0x45, - kVK_ANSI_KeypadClear = 0x47, - kVK_ANSI_KeypadDivide = 0x4B, - kVK_ANSI_KeypadEnter = 0x4C, - kVK_ANSI_KeypadMinus = 0x4E, - kVK_ANSI_KeypadEquals = 0x51, - kVK_ANSI_Keypad0 = 0x52, - kVK_ANSI_Keypad1 = 0x53, - kVK_ANSI_Keypad2 = 0x54, - kVK_ANSI_Keypad3 = 0x55, - kVK_ANSI_Keypad4 = 0x56, - kVK_ANSI_Keypad5 = 0x57, - kVK_ANSI_Keypad6 = 0x58, - kVK_ANSI_Keypad7 = 0x59, - kVK_ANSI_Keypad8 = 0x5B, - kVK_ANSI_Keypad9 = 0x5C -}; - -/* keycodes for keys that are independent of keyboard layout*/ -enum -{ - kVK_Return = 0x24, - kVK_Tab = 0x30, - kVK_Space = 0x31, - kVK_Delete = 0x33, - kVK_Escape = 0x35, - kVK_Command = 0x37, - kVK_Shift = 0x38, - kVK_CapsLock = 0x39, - kVK_Option = 0x3A, - kVK_Control = 0x3B, - kVK_RightShift = 0x3C, - kVK_RightOption = 0x3D, - kVK_RightControl = 0x3E, - kVK_Function = 0x3F, - kVK_F17 = 0x40, - kVK_VolumeUp = 0x48, - kVK_VolumeDown = 0x49, - kVK_Mute = 0x4A, - kVK_F18 = 0x4F, - kVK_F19 = 0x50, - kVK_F20 = 0x5A, - kVK_F5 = 0x60, - kVK_F6 = 0x61, - kVK_F7 = 0x62, - kVK_F3 = 0x63, - kVK_F8 = 0x64, - kVK_F9 = 0x65, - kVK_F11 = 0x67, - kVK_F13 = 0x69, - kVK_F16 = 0x6A, - kVK_F14 = 0x6B, - kVK_F10 = 0x6D, - kVK_F12 = 0x6F, - kVK_F15 = 0x71, - kVK_Help = 0x72, - kVK_Home = 0x73, - kVK_PageUp = 0x74, - kVK_ForwardDelete = 0x75, - kVK_F4 = 0x76, - kVK_End = 0x77, - kVK_F2 = 0x78, - kVK_PageDown = 0x79, - kVK_F1 = 0x7A, - kVK_LeftArrow = 0x7B, - kVK_RightArrow = 0x7C, - kVK_DownArrow = 0x7D, - kVK_UpArrow = 0x7E -}; - -//------------------------------------------------------------------------------------------ -Boolean GetDictionaryBoolean(CFDictionaryRef theDict, const void *key) -{ - // get a boolean from the dictionary - Boolean value = false; - CFBooleanRef boolRef; - boolRef = (CFBooleanRef)CFDictionaryGetValue(theDict, key); - if (boolRef != NULL) - value = CFBooleanGetValue(boolRef); - return value; -} -//------------------------------------------------------------------------------------------ -long GetDictionaryLong(CFDictionaryRef theDict, const void *key) -{ - // get a long from the dictionary - long value = 0; - CFNumberRef numRef; - numRef = (CFNumberRef)CFDictionaryGetValue(theDict, key); - if (numRef != NULL) - CFNumberGetValue(numRef, kCFNumberLongType, &value); - return value; -} - -static bool firstLaunch = true; - -@implementation CIrrDelegateOSX { - CIrrDeviceMacOSX *Device; - bool Quit; -} - -- (id)initWithDevice:(CIrrDeviceMacOSX *)device -{ - self = [super init]; - - if (self) - Device = device; - - Quit = false; - - return (self); -} - -- (void)applicationDidFinishLaunching:(NSNotification *)notification -{ - Quit = false; -} - -- (void)orderFrontStandardAboutPanel:(id)sender -{ - [NSApp orderFrontStandardAboutPanel:sender]; -} - -- (void)unhideAllApplications:(id)sender -{ - [NSApp unhideAllApplications:sender]; -} - -- (void)hide:(id)sender -{ - [NSApp hide:sender]; -} - -- (void)hideOtherApplications:(id)sender -{ - [NSApp hideOtherApplications:sender]; -} - -- (void)terminate:(id)sender -{ - Quit = true; -} - -- (void)windowWillClose:(id)sender -{ - Device->setWindow(nil); - Quit = true; -} - -- (NSSize)windowWillResize:(NSWindow *)window toSize:(NSSize)proposedFrameSize -{ - if (Device->isResizable()) - return proposedFrameSize; - else - return [window frame].size; -} - -- (void)windowDidResize:(NSNotification *)aNotification -{ - NSWindow *window; - NSRect frame; - - window = [aNotification object]; - frame = [window frame]; - Device->setResize((int)frame.size.width, (int)frame.size.height); -} - -- (BOOL)isQuit -{ - return (Quit); -} - -@end - -//! constructor -CIrrDeviceMacOSX::CIrrDeviceMacOSX(const SIrrlichtCreationParameters ¶m) : - CIrrDeviceStub(param), Window(NULL), Display(NULL), - DeviceWidth(0), DeviceHeight(0), - ScreenWidth(0), ScreenHeight(0), MouseButtonStates(0), - IsActive(true), IsFullscreen(false), IsShiftDown(false), IsControlDown(false), IsResizable(false) -{ - struct utsname name; - - if (firstLaunch) { - firstLaunch = false; - - if (!CreationParams.WindowId) { - [[NSAutoreleasePool alloc] init]; - [[NSApplication sharedApplication] activateIgnoringOtherApps:YES]; - [[NSApplication sharedApplication] setDelegate:[[[CIrrDelegateOSX alloc] initWithDevice:this] autorelease]]; - - // Create menu - - NSString *bundleName = [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleName"]; - if (bundleName == nil) - bundleName = @"Irrlicht"; - - NSMenu *mainMenu = [[[NSMenu alloc] initWithTitle:@"MainMenu"] autorelease]; - NSMenu *menu = [[[NSMenu alloc] initWithTitle:bundleName] autorelease]; - NSMenuItem *menuItem = [mainMenu addItemWithTitle:bundleName action:nil keyEquivalent:@""]; - [mainMenu setSubmenu:menu forItem:menuItem]; - menuItem = [menu addItemWithTitle:@"Quit" action:@selector(terminate:) keyEquivalent:@"q"]; - [menuItem setKeyEquivalentModifierMask:NSCommandKeyMask]; - - [NSApp setMainMenu:mainMenu]; - - [NSApp finishLaunching]; - } - - NSString *path = [[NSBundle mainBundle] bundlePath]; - if (path != nil) { - path = [path stringByAppendingString:@"/Contents/Resources"]; - chdir([path fileSystemRepresentation]); - [path release]; - } - } - - uname(&name); - Operator = new COSOperator(name.version); - os::Printer::log(name.version, ELL_INFORMATION); - - initKeycodes(); - - bool success = true; - - if (CreationParams.DriverType != video::EDT_NULL) - success = createWindow(); - - // in case of failure, one can check VideoDriver for initialization - if (!success) - return; - - setResizable(false); - CursorControl = new CCursorControl(CreationParams.WindowSize, this); - - createDriver(); - createGUIAndScene(); -} - -CIrrDeviceMacOSX::~CIrrDeviceMacOSX() -{ - [NSApp setPresentationOptions:(NSApplicationPresentationDefault)]; - closeDevice(); -#if defined(_IRR_COMPILE_WITH_JOYSTICK_EVENTS_) - for (u32 joystick = 0; joystick < ActiveJoysticks.size(); ++joystick) { - if (ActiveJoysticks[joystick].interface) - closeJoystickDevice(&ActiveJoysticks[joystick]); - } -#endif -} - -void CIrrDeviceMacOSX::closeDevice() -{ - if (Window != nil) { - [Window setIsVisible:FALSE]; - [Window setReleasedWhenClosed:TRUE]; - [Window release]; - Window = nil; - } - - IsFullscreen = false; - IsActive = false; -} - -bool CIrrDeviceMacOSX::createWindow() -{ - CGDisplayErr error; - bool result = false; - Display = CGMainDisplayID(); - - CGRect displayRect; - CGDisplayModeRef displaymode, olddisplaymode; - - ScreenWidth = (int)CGDisplayPixelsWide(Display); - ScreenHeight = (int)CGDisplayPixelsHigh(Display); - - const NSBackingStoreType type = (CreationParams.DriverType == video::EDT_OPENGL) ? NSBackingStoreBuffered : NSBackingStoreNonretained; - - // TODO: fullscreen - // if (!CreationParams.Fullscreen) - { - if (!CreationParams.WindowId) { // create another window when WindowId is null - int x = (CreationParams.WindowPosition.X > 0) ? CreationParams.WindowPosition.X : 0; - int y = (CreationParams.WindowPosition.Y > 0) ? CreationParams.WindowPosition.Y : 0; - - if (CreationParams.WindowPosition.Y > -1) { - int screenHeight = [[[NSScreen screens] objectAtIndex:0] frame].size.height; - y = screenHeight - y - CreationParams.WindowSize.Height; - } - - Window = [[NSWindow alloc] initWithContentRect:NSMakeRect(x, y, CreationParams.WindowSize.Width, CreationParams.WindowSize.Height) styleMask:NSTitledWindowMask + NSClosableWindowMask + NSResizableWindowMask backing:type defer:FALSE]; - - if (CreationParams.WindowPosition.X == -1 && CreationParams.WindowPosition.Y == -1) - [Window center]; - } - - DeviceWidth = CreationParams.WindowSize.Width; - DeviceHeight = CreationParams.WindowSize.Height; - - result = true; - } - - if (result) { - if (Window) { - [Window setDelegate:(CIrrDelegateOSX *)[NSApp delegate]]; - [Window setAcceptsMouseMovedEvents:TRUE]; - [Window setIsVisible:TRUE]; - [Window makeKeyAndOrderFront:nil]; - } - } - - return result; -} - -void CIrrDeviceMacOSX::setResize(int width, int height) -{ - // set new window size - DeviceWidth = width; - DeviceHeight = height; - -#if defined(_IRR_COMPILE_WITH_OPENGL_) - // update the size of the opengl rendering context - if (CreationParams.DriverType == video::EDT_OPENGL) { - NSOpenGLContext *Context = (NSOpenGLContext *)ContextManager->getContext().OpenGLOSX.Context; - - if (Context) - [Context update]; - } -#endif - - // resize the driver to the inner pane size - if (Window) { - NSRect driverFrame = [Window contentRectForFrameRect:[Window frame]]; - getVideoDriver()->OnResize(core::dimension2d((s32)driverFrame.size.width, (s32)driverFrame.size.height)); - DeviceWidth = (s32)driverFrame.size.width; - DeviceHeight = (s32)driverFrame.size.height; - } else - getVideoDriver()->OnResize(core::dimension2d((s32)width, (s32)height)); -} - -void CIrrDeviceMacOSX::createDriver() -{ - switch (CreationParams.DriverType) { - case video::EDT_OPENGL: -#ifdef _IRR_COMPILE_WITH_OPENGL_ - { - video::SExposedVideoData data; - data.OpenGLOSX.Window = Window; - ContextManager = new video::CNSOGLManager(); - ContextManager->initialize(CreationParams, data); - VideoDriver = video::createOpenGLDriver(CreationParams, FileSystem, ContextManager); - if (!VideoDriver) { - os::Printer::log("Could not create OpenGL driver.", ELL_ERROR); - } - - if (Window) { - [[Window contentView] setWantsBestResolutionOpenGLSurface:NO]; - [(NSOpenGLContext *)ContextManager->getContext().OpenGLOSX.Context setView:[Window contentView]]; - } else { - [(NSView *)CreationParams.WindowId setWantsBestResolutionOpenGLSurface:NO]; - [(NSOpenGLContext *)ContextManager->getContext().OpenGLOSX.Context setView:(NSView *)CreationParams.WindowId]; - } - } -#else - os::Printer::log("No OpenGL support compiled in.", ELL_ERROR); -#endif - break; - - case video::EDT_OPENGL3: - case video::EDT_OGLES2: - os::Printer::log("This driver is not available on OSX.", ELL_ERROR); - break; - - case video::EDT_NULL: - VideoDriver = video::createNullDriver(FileSystem, CreationParams.WindowSize); - break; - - default: - os::Printer::log("Unable to create video driver of unknown type.", ELL_ERROR); - break; - } -} - -bool CIrrDeviceMacOSX::run() -{ - NSAutoreleasePool *Pool = [[NSAutoreleasePool alloc] init]; - - NSEvent *event; - SEvent ievent; - - os::Timer::tick(); - storeMouseLocation(); - - event = [NSApp nextEventMatchingMask:NSAnyEventMask untilDate:[NSDate distantPast] inMode:NSDefaultRunLoopMode dequeue:YES]; - if (event != nil) { - bzero(&ievent, sizeof(ievent)); - - switch ([(NSEvent *)event type]) { - case NSKeyDown: - postKeyEvent(event, ievent, true); - break; - - case NSKeyUp: - postKeyEvent(event, ievent, false); - break; - - case NSFlagsChanged: - ievent.EventType = EET_KEY_INPUT_EVENT; - ievent.KeyInput.Shift = ([(NSEvent *)event modifierFlags] & NSShiftKeyMask) != 0; - ievent.KeyInput.Control = ([(NSEvent *)event modifierFlags] & NSControlKeyMask) != 0; - - if (IsShiftDown != ievent.KeyInput.Shift) { - ievent.KeyInput.Char = KEY_SHIFT; - ievent.KeyInput.Key = KEY_SHIFT; - ievent.KeyInput.PressedDown = ievent.KeyInput.Shift; - - IsShiftDown = ievent.KeyInput.Shift; - - postEventFromUser(ievent); - } - - if (IsControlDown != ievent.KeyInput.Control) { - ievent.KeyInput.Char = KEY_CONTROL; - ievent.KeyInput.Key = KEY_CONTROL; - ievent.KeyInput.PressedDown = ievent.KeyInput.Control; - - IsControlDown = ievent.KeyInput.Control; - - postEventFromUser(ievent); - } - - [NSApp sendEvent:event]; - break; - - case NSLeftMouseDown: - ievent.EventType = EET_MOUSE_INPUT_EVENT; - ievent.MouseInput.Event = EMIE_LMOUSE_PRESSED_DOWN; - MouseButtonStates |= EMBSM_LEFT; - ievent.MouseInput.ButtonStates = MouseButtonStates; - postMouseEvent(event, ievent); - break; - - case NSLeftMouseUp: - ievent.EventType = EET_MOUSE_INPUT_EVENT; - MouseButtonStates &= !EMBSM_LEFT; - ievent.MouseInput.ButtonStates = MouseButtonStates; - ievent.MouseInput.Event = EMIE_LMOUSE_LEFT_UP; - postMouseEvent(event, ievent); - break; - - case NSOtherMouseDown: - ievent.EventType = EET_MOUSE_INPUT_EVENT; - ievent.MouseInput.Event = EMIE_MMOUSE_PRESSED_DOWN; - MouseButtonStates |= EMBSM_MIDDLE; - ievent.MouseInput.ButtonStates = MouseButtonStates; - postMouseEvent(event, ievent); - break; - - case NSOtherMouseUp: - ievent.EventType = EET_MOUSE_INPUT_EVENT; - MouseButtonStates &= !EMBSM_MIDDLE; - ievent.MouseInput.ButtonStates = MouseButtonStates; - ievent.MouseInput.Event = EMIE_MMOUSE_LEFT_UP; - postMouseEvent(event, ievent); - break; - - case NSMouseMoved: - case NSLeftMouseDragged: - case NSRightMouseDragged: - case NSOtherMouseDragged: - ievent.EventType = EET_MOUSE_INPUT_EVENT; - ievent.MouseInput.Event = EMIE_MOUSE_MOVED; - ievent.MouseInput.ButtonStates = MouseButtonStates; - postMouseEvent(event, ievent); - break; - - case NSRightMouseDown: - ievent.EventType = EET_MOUSE_INPUT_EVENT; - ievent.MouseInput.Event = EMIE_RMOUSE_PRESSED_DOWN; - MouseButtonStates |= EMBSM_RIGHT; - ievent.MouseInput.ButtonStates = MouseButtonStates; - postMouseEvent(event, ievent); - break; - - case NSRightMouseUp: - ievent.EventType = EET_MOUSE_INPUT_EVENT; - ievent.MouseInput.Event = EMIE_RMOUSE_LEFT_UP; - MouseButtonStates &= !EMBSM_RIGHT; - ievent.MouseInput.ButtonStates = MouseButtonStates; - postMouseEvent(event, ievent); - break; - - case NSScrollWheel: - ievent.EventType = EET_MOUSE_INPUT_EVENT; - ievent.MouseInput.Event = EMIE_MOUSE_WHEEL; - ievent.MouseInput.Wheel = [(NSEvent *)event deltaY]; - if (ievent.MouseInput.Wheel < 1.0f) - ievent.MouseInput.Wheel *= 10.0f; - else - ievent.MouseInput.Wheel *= 5.0f; - ievent.MouseInput.ButtonStates = MouseButtonStates; - postMouseEvent(event, ievent); - break; - - default: - [NSApp sendEvent:event]; - break; - } - } - - pollJoysticks(); - - [Pool release]; - - return (![[NSApp delegate] isQuit] && IsActive); -} - -//! Pause the current process for the minimum time allowed only to allow other processes to execute -void CIrrDeviceMacOSX::yield() -{ - struct timespec ts = {0, 0}; - nanosleep(&ts, NULL); -} - -//! Pause execution and let other processes to run for a specified amount of time. -void CIrrDeviceMacOSX::sleep(u32 timeMs, bool pauseTimer = false) -{ - bool wasStopped = Timer ? Timer->isStopped() : true; - - struct timespec ts; - ts.tv_sec = (time_t)(timeMs / 1000); - ts.tv_nsec = (long)(timeMs % 1000) * 1000000; - - if (pauseTimer && !wasStopped) - Timer->stop(); - - nanosleep(&ts, NULL); - - if (pauseTimer && !wasStopped) - Timer->start(); -} - -void CIrrDeviceMacOSX::setWindowCaption(const wchar_t *text) -{ - if (Window != NULL) { - if (text) { - size_t numBytes = wcslen(text) * sizeof(wchar_t); - -#ifdef __BIG_ENDIAN__ - NSStringEncoding encode = sizeof(wchar_t) == 4 ? NSUTF32BigEndianStringEncoding : NSUTF16BigEndianStringEncoding; -#else - NSStringEncoding encode = sizeof(wchar_t) == 4 ? NSUTF32LittleEndianStringEncoding : NSUTF16LittleEndianStringEncoding; -#endif - NSString *name = [[NSString alloc] initWithBytes:text length:numBytes encoding:encode]; - if (name) { - [Window setTitle:name]; - [name release]; - } - } else { - [Window setTitle:@""]; - } - } -} - -bool CIrrDeviceMacOSX::isWindowActive() const -{ - return (IsActive); -} - -bool CIrrDeviceMacOSX::isWindowFocused() const -{ - if (Window != NULL) - return [Window isKeyWindow]; - return false; -} - -bool CIrrDeviceMacOSX::isWindowMinimized() const -{ - if (Window != NULL) - return [Window isMiniaturized]; - return false; -} - -void CIrrDeviceMacOSX::postKeyEvent(void *event, SEvent &ievent, bool pressed) -{ - NSString *str; - std::map::const_iterator iter; - unsigned int c, mkey, mchar; - const unsigned char *cStr; - BOOL skipCommand; - - str = [(NSEvent *)event characters]; - if ((str != nil) && ([str length] > 0)) { - mkey = mchar = 0; - skipCommand = false; - c = [str characterAtIndex:0]; - mchar = c; - - iter = KeyCodes.find([(NSEvent *)event keyCode]); - if (iter != KeyCodes.end()) - mkey = (*iter).second; - else if ((iter = KeyCodes.find(c)) != KeyCodes.end()) - mkey = (*iter).second; - else { - // workaround for period character - if (c == 0x2E) { - mkey = KEY_PERIOD; - mchar = '.'; - } else { - cStr = (unsigned char *)[str cStringUsingEncoding:NSWindowsCP1252StringEncoding]; - if (cStr != NULL && strlen((char *)cStr) > 0) { - mchar = cStr[0]; - mkey = toupper(mchar); - if ([(NSEvent *)event modifierFlags] & NSCommandKeyMask) { - if (mkey == 'C' || mkey == 'V' || mkey == 'X') { - mchar = 0; - skipCommand = true; - } - } - } - } - } - - ievent.EventType = EET_KEY_INPUT_EVENT; - ievent.KeyInput.Key = (EKEY_CODE)mkey; - ievent.KeyInput.PressedDown = pressed; - ievent.KeyInput.Shift = ([(NSEvent *)event modifierFlags] & NSShiftKeyMask) != 0; - ievent.KeyInput.Control = ([(NSEvent *)event modifierFlags] & NSControlKeyMask) != 0; - ievent.KeyInput.Char = mchar; - - if (skipCommand) - ievent.KeyInput.Control = true; - else if ([(NSEvent *)event modifierFlags] & NSCommandKeyMask) - [NSApp sendEvent:(NSEvent *)event]; - - postEventFromUser(ievent); - } -} - -void CIrrDeviceMacOSX::postMouseEvent(void *event, SEvent &ievent) -{ - bool post = true; - - if (Window != NULL) { - ievent.MouseInput.X = (int)[(NSEvent *)event locationInWindow].x; - ievent.MouseInput.Y = DeviceHeight - (int)[(NSEvent *)event locationInWindow].y; - - if (ievent.MouseInput.Y < 0) - post = false; - } else { - CGEventRef ourEvent = CGEventCreate(NULL); - CGPoint point = CGEventGetLocation(ourEvent); - CFRelease(ourEvent); - - ievent.MouseInput.X = (int)point.x; - ievent.MouseInput.Y = (int)point.y; - - if (ievent.MouseInput.Y < 0) - post = false; - } - - if (post) { - ievent.MouseInput.Shift = ([(NSEvent *)event modifierFlags] & NSShiftKeyMask) != 0; - ievent.MouseInput.Control = ([(NSEvent *)event modifierFlags] & NSControlKeyMask) != 0; - - postEventFromUser(ievent); - } - - [NSApp sendEvent:(NSEvent *)event]; -} - -void CIrrDeviceMacOSX::storeMouseLocation() -{ - int x, y; - - if (Window != NULL) { - NSPoint p; - p = [NSEvent mouseLocation]; - p = [Window convertScreenToBase:p]; - x = (int)p.x; - y = DeviceHeight - (int)p.y; - } else { - // Do we still need this? - CGEventRef ourEvent = CGEventCreate(NULL); - CGPoint point = CGEventGetLocation(ourEvent); - CFRelease(ourEvent); - - x = (int)point.x; - y = (int)point.y; - - const core::position2di &curr = ((CCursorControl *)CursorControl)->getPosition(true); - if (curr.X != x || curr.Y != y) { - SEvent ievent; - ievent.EventType = EET_MOUSE_INPUT_EVENT; - ievent.MouseInput.Event = EMIE_MOUSE_MOVED; - ievent.MouseInput.X = x; - ievent.MouseInput.Y = y; - ievent.MouseInput.ButtonStates = MouseButtonStates; - postEventFromUser(ievent); - } - } - - ((CCursorControl *)CursorControl)->updateInternalCursorPosition(x, y); -} - -void CIrrDeviceMacOSX::setMouseLocation(int x, int y) -{ - NSPoint p; - CGPoint c; - - if (Window != NULL) { - // Irrlicht window exists - p.x = (float)x; - p.y = (float)(DeviceHeight - y); - p = [Window convertBaseToScreen:p]; - p.y = ScreenHeight - p.y; - } else { - p.x = (float)x; - p.y = (float)y + (ScreenHeight - DeviceHeight); - } - - c.x = p.x; - c.y = p.y; - - CGWarpMouseCursorPosition(c); - CGAssociateMouseAndMouseCursorPosition(YES); -} - -void CIrrDeviceMacOSX::setCursorVisible(bool visible) -{ - if (visible) - CGDisplayShowCursor(CGMainDisplayID()); - else - CGDisplayHideCursor(CGMainDisplayID()); -} - -void CIrrDeviceMacOSX::setWindow(NSWindow *window) -{ - Window = window; -} - -void CIrrDeviceMacOSX::initKeycodes() -{ - KeyCodes[kVK_UpArrow] = KEY_UP; - KeyCodes[kVK_DownArrow] = KEY_DOWN; - KeyCodes[kVK_LeftArrow] = KEY_LEFT; - KeyCodes[kVK_RightArrow] = KEY_RIGHT; - KeyCodes[kVK_F1] = KEY_F1; - KeyCodes[kVK_F2] = KEY_F2; - KeyCodes[kVK_F3] = KEY_F3; - KeyCodes[kVK_F4] = KEY_F4; - KeyCodes[kVK_F5] = KEY_F5; - KeyCodes[kVK_F6] = KEY_F6; - KeyCodes[kVK_F7] = KEY_F7; - KeyCodes[kVK_F8] = KEY_F8; - KeyCodes[kVK_F9] = KEY_F9; - KeyCodes[kVK_F10] = KEY_F10; - KeyCodes[kVK_F11] = KEY_F11; - KeyCodes[kVK_F12] = KEY_F12; - KeyCodes[kVK_F13] = KEY_F13; - KeyCodes[kVK_F14] = KEY_F14; - KeyCodes[kVK_F15] = KEY_F15; - KeyCodes[kVK_F16] = KEY_F16; - KeyCodes[kVK_F17] = KEY_F17; - KeyCodes[kVK_F18] = KEY_F18; - KeyCodes[kVK_F19] = KEY_F19; - KeyCodes[kVK_F20] = KEY_F20; - KeyCodes[kVK_Home] = KEY_HOME; - KeyCodes[kVK_End] = KEY_END; - KeyCodes[NSInsertFunctionKey] = KEY_INSERT; - KeyCodes[kVK_ForwardDelete] = KEY_DELETE; - KeyCodes[kVK_Help] = KEY_HELP; - KeyCodes[NSSelectFunctionKey] = KEY_SELECT; - KeyCodes[NSPrintFunctionKey] = KEY_PRINT; - KeyCodes[NSExecuteFunctionKey] = KEY_EXECUT; - KeyCodes[NSPrintScreenFunctionKey] = KEY_SNAPSHOT; - KeyCodes[NSPauseFunctionKey] = KEY_PAUSE; - KeyCodes[NSScrollLockFunctionKey] = KEY_SCROLL; - KeyCodes[kVK_Delete] = KEY_BACK; - KeyCodes[kVK_Tab] = KEY_TAB; - KeyCodes[kVK_Return] = KEY_RETURN; - KeyCodes[kVK_Escape] = KEY_ESCAPE; - KeyCodes[kVK_Control] = KEY_CONTROL; - KeyCodes[kVK_RightControl] = KEY_RCONTROL; - KeyCodes[kVK_Command] = KEY_MENU; - KeyCodes[kVK_Shift] = KEY_SHIFT; - KeyCodes[kVK_RightShift] = KEY_RSHIFT; - KeyCodes[kVK_Space] = KEY_SPACE; - - KeyCodes[kVK_ANSI_A] = KEY_KEY_A; - KeyCodes[kVK_ANSI_B] = KEY_KEY_B; - KeyCodes[kVK_ANSI_C] = KEY_KEY_C; - KeyCodes[kVK_ANSI_D] = KEY_KEY_D; - KeyCodes[kVK_ANSI_E] = KEY_KEY_E; - KeyCodes[kVK_ANSI_F] = KEY_KEY_F; - KeyCodes[kVK_ANSI_G] = KEY_KEY_G; - KeyCodes[kVK_ANSI_H] = KEY_KEY_H; - KeyCodes[kVK_ANSI_I] = KEY_KEY_I; - KeyCodes[kVK_ANSI_J] = KEY_KEY_J; - KeyCodes[kVK_ANSI_K] = KEY_KEY_K; - KeyCodes[kVK_ANSI_L] = KEY_KEY_L; - KeyCodes[kVK_ANSI_M] = KEY_KEY_M; - KeyCodes[kVK_ANSI_N] = KEY_KEY_N; - KeyCodes[kVK_ANSI_O] = KEY_KEY_O; - KeyCodes[kVK_ANSI_P] = KEY_KEY_P; - KeyCodes[kVK_ANSI_Q] = KEY_KEY_Q; - KeyCodes[kVK_ANSI_R] = KEY_KEY_R; - KeyCodes[kVK_ANSI_S] = KEY_KEY_S; - KeyCodes[kVK_ANSI_T] = KEY_KEY_T; - KeyCodes[kVK_ANSI_U] = KEY_KEY_U; - KeyCodes[kVK_ANSI_V] = KEY_KEY_V; - KeyCodes[kVK_ANSI_W] = KEY_KEY_W; - KeyCodes[kVK_ANSI_X] = KEY_KEY_X; - KeyCodes[kVK_ANSI_X] = KEY_KEY_X; - KeyCodes[kVK_ANSI_Y] = KEY_KEY_Y; - KeyCodes[kVK_ANSI_Z] = KEY_KEY_Z; - - KeyCodes[kVK_ANSI_0] = KEY_KEY_0; - KeyCodes[kVK_ANSI_1] = KEY_KEY_1; - KeyCodes[kVK_ANSI_2] = KEY_KEY_2; - KeyCodes[kVK_ANSI_3] = KEY_KEY_3; - KeyCodes[kVK_ANSI_4] = KEY_KEY_4; - KeyCodes[kVK_ANSI_5] = KEY_KEY_5; - KeyCodes[kVK_ANSI_6] = KEY_KEY_6; - KeyCodes[kVK_ANSI_7] = KEY_KEY_7; - KeyCodes[kVK_ANSI_8] = KEY_KEY_8; - KeyCodes[kVK_ANSI_9] = KEY_KEY_9; - - KeyCodes[kVK_ANSI_Slash] = KEY_DIVIDE; - KeyCodes[kVK_ANSI_Comma] = KEY_COMMA; - KeyCodes[kVK_ANSI_Period] = KEY_PERIOD; - KeyCodes[kVK_PageUp] = KEY_PRIOR; - KeyCodes[kVK_PageDown] = KEY_NEXT; - - KeyCodes[kVK_ANSI_Keypad0] = KEY_NUMPAD0; - KeyCodes[kVK_ANSI_Keypad1] = KEY_NUMPAD1; - KeyCodes[kVK_ANSI_Keypad2] = KEY_NUMPAD2; - KeyCodes[kVK_ANSI_Keypad3] = KEY_NUMPAD3; - KeyCodes[kVK_ANSI_Keypad4] = KEY_NUMPAD4; - KeyCodes[kVK_ANSI_Keypad5] = KEY_NUMPAD5; - KeyCodes[kVK_ANSI_Keypad6] = KEY_NUMPAD6; - KeyCodes[kVK_ANSI_Keypad7] = KEY_NUMPAD7; - KeyCodes[kVK_ANSI_Keypad8] = KEY_NUMPAD8; - KeyCodes[kVK_ANSI_Keypad9] = KEY_NUMPAD9; - - KeyCodes[kVK_ANSI_KeypadDecimal] = KEY_DECIMAL; - KeyCodes[kVK_ANSI_KeypadMultiply] = KEY_MULTIPLY; - KeyCodes[kVK_ANSI_KeypadPlus] = KEY_PLUS; - KeyCodes[kVK_ANSI_KeypadClear] = KEY_OEM_CLEAR; - KeyCodes[kVK_ANSI_KeypadDivide] = KEY_DIVIDE; - KeyCodes[kVK_ANSI_KeypadEnter] = KEY_RETURN; - KeyCodes[kVK_ANSI_KeypadMinus] = KEY_SUBTRACT; - - KeyCodes[kVK_ANSI_LeftBracket] = KEY_OEM_4; - KeyCodes[kVK_ANSI_Backslash] = KEY_OEM_5; - KeyCodes[kVK_ANSI_RightBracket] = KEY_OEM_6; -} - -//! Sets if the window should be resizable in windowed mode. -void CIrrDeviceMacOSX::setResizable(bool resize) -{ - IsResizable = resize; -#if 0 - if (resize) - [Window setStyleMask:NSTitledWindowMask|NSClosableWindowMask|NSMiniaturizableWindowMask|NSResizableWindowMask]; - else - [Window setStyleMask:NSTitledWindowMask|NSClosableWindowMask]; -#endif -} - -bool CIrrDeviceMacOSX::isResizable() const -{ - return IsResizable; -} - -void CIrrDeviceMacOSX::minimizeWindow() -{ - if (Window != NULL) - [Window miniaturize:[NSApp self]]; -} - -//! Maximizes the window if possible. -void CIrrDeviceMacOSX::maximizeWindow() -{ - // todo: implement -} - -//! get the window to normal size if possible. -void CIrrDeviceMacOSX::restoreWindow() -{ - [Window deminiaturize:[NSApp self]]; -} - -//! Get the position of this window on screen -core::position2di CIrrDeviceMacOSX::getWindowPosition() -{ - NSRect rect = [Window frame]; - int screenHeight = [[[NSScreen screens] objectAtIndex:0] frame].size.height; - return core::position2di(rect.origin.x, screenHeight - rect.origin.y - rect.size.height); -} - -#if defined(_IRR_COMPILE_WITH_JOYSTICK_EVENTS_) -static void joystickRemovalCallback(void *target, - IOReturn result, void *refcon, void *sender) -{ - JoystickInfo *joy = (JoystickInfo *)refcon; - joy->removed = 1; -} -#endif // _IRR_COMPILE_WITH_JOYSTICK_EVENTS_ - -bool CIrrDeviceMacOSX::activateJoysticks(core::array &joystickInfo) -{ -#if defined(_IRR_COMPILE_WITH_JOYSTICK_EVENTS_) - ActiveJoysticks.clear(); - joystickInfo.clear(); - - io_object_t hidObject = 0; - io_iterator_t hidIterator = 0; - IOReturn result = kIOReturnSuccess; - mach_port_t masterPort = 0; - CFMutableDictionaryRef hidDictionaryRef = NULL; - - result = IOMasterPort(bootstrap_port, &masterPort); - if (kIOReturnSuccess != result) { - os::Printer::log("initialiseJoysticks IOMasterPort failed", ELL_ERROR); - return false; - } - - hidDictionaryRef = IOServiceMatching(kIOHIDDeviceKey); - if (!hidDictionaryRef) { - os::Printer::log("initialiseJoysticks IOServiceMatching failed", ELL_ERROR); - return false; - } - result = IOServiceGetMatchingServices(masterPort, hidDictionaryRef, &hidIterator); - - if (kIOReturnSuccess != result) { - os::Printer::log("initialiseJoysticks IOServiceGetMatchingServices failed", ELL_ERROR); - return false; - } - - // no joysticks just return - if (!hidIterator) - return false; - - u32 jindex = 0u; - while ((hidObject = IOIteratorNext(hidIterator))) { - JoystickInfo info; - - // get dictionary for HID properties - CFMutableDictionaryRef hidProperties = 0; - - kern_return_t kern_result = IORegistryEntryCreateCFProperties(hidObject, &hidProperties, kCFAllocatorDefault, kNilOptions); - if ((kern_result == KERN_SUCCESS) && hidProperties) { - HRESULT plugInResult = S_OK; - SInt32 score = 0; - IOCFPlugInInterface **ppPlugInInterface = NULL; - result = IOCreatePlugInInterfaceForService(hidObject, kIOHIDDeviceUserClientTypeID, - kIOCFPlugInInterfaceID, &ppPlugInInterface, &score); - if (kIOReturnSuccess == result) { - plugInResult = (*ppPlugInInterface)->QueryInterface(ppPlugInInterface, CFUUIDGetUUIDBytes(kIOHIDDeviceInterfaceID), (void **)&(info.interface)); - if (plugInResult != S_OK) - os::Printer::log("initialiseJoysticks query HID class device interface failed", ELL_ERROR); - (*ppPlugInInterface)->Release(ppPlugInInterface); - } else - continue; - - if (info.interface != NULL) { - result = (*(info.interface))->open(info.interface, 0); - if (result == kIOReturnSuccess) { - (*(info.interface))->setRemovalCallback(info.interface, joystickRemovalCallback, &info, &info); - getJoystickDeviceInfo(hidObject, hidProperties, &info); - - // get elements - CFTypeRef refElementTop = CFDictionaryGetValue(hidProperties, CFSTR(kIOHIDElementKey)); - if (refElementTop) { - CFTypeID type = CFGetTypeID(refElementTop); - if (type == CFArrayGetTypeID()) { - CFRange range = {0, CFArrayGetCount((CFArrayRef)refElementTop)}; - info.numActiveJoysticks = ActiveJoysticks.size(); - CFArrayApplyFunction((CFArrayRef)refElementTop, range, getJoystickComponentArrayHandler, &info); - } - } - } else { - CFRelease(hidProperties); - os::Printer::log("initialiseJoysticks Open interface failed", ELL_ERROR); - continue; - } - - CFRelease(hidProperties); - - result = IOObjectRelease(hidObject); - - if ((info.usagePage != kHIDPage_GenericDesktop) || - ((info.usage != kHIDUsage_GD_Joystick && - info.usage != kHIDUsage_GD_GamePad && - info.usage != kHIDUsage_GD_MultiAxisController))) { - closeJoystickDevice(&info); - continue; - } - - for (u32 i = 0; i < 6; ++i) - info.persistentData.JoystickEvent.Axis[i] = 0; - - ActiveJoysticks.push_back(info); - - SJoystickInfo returnInfo; - returnInfo.Joystick = jindex; - returnInfo.Axes = info.axes; - // returnInfo.Hats = info.hats; - returnInfo.Buttons = info.buttons; - returnInfo.Name = info.joystickName; - returnInfo.PovHat = SJoystickInfo::POV_HAT_UNKNOWN; - ++jindex; - - // if (info.hatComp.size()) - // returnInfo.PovHat = SJoystickInfo::POV_HAT_PRESENT; - // else - // returnInfo.PovHat = SJoystickInfo::POV_HAT_ABSENT; - - joystickInfo.push_back(returnInfo); - } - - } else { - continue; - } - } - result = IOObjectRelease(hidIterator); - - return true; -#endif // _IRR_COMPILE_WITH_JOYSTICK_EVENTS_ - - return false; -} - -void CIrrDeviceMacOSX::pollJoysticks() -{ -#if defined(_IRR_COMPILE_WITH_JOYSTICK_EVENTS_) - if (0 == ActiveJoysticks.size()) - return; - - u32 joystick; - for (joystick = 0; joystick < ActiveJoysticks.size(); ++joystick) { - if (ActiveJoysticks[joystick].removed) - continue; - - bool found = false; - ActiveJoysticks[joystick].persistentData.JoystickEvent.Joystick = joystick; - - if (ActiveJoysticks[joystick].interface) { - for (u32 n = 0; n < ActiveJoysticks[joystick].axisComp.size(); n++) { - IOReturn result = kIOReturnSuccess; - IOHIDEventStruct hidEvent; - hidEvent.value = 0; - result = (*(ActiveJoysticks[joystick].interface))->getElementValue(ActiveJoysticks[joystick].interface, ActiveJoysticks[joystick].axisComp[n].cookie, &hidEvent); - if (kIOReturnSuccess == result) { - const f32 min = -32768.0f; - const f32 max = 32767.0f; - const f32 deviceScale = max - min; - const f32 readScale = (f32)ActiveJoysticks[joystick].axisComp[n].maxRead - (f32)ActiveJoysticks[joystick].axisComp[n].minRead; - - if (hidEvent.value < ActiveJoysticks[joystick].axisComp[n].minRead) - ActiveJoysticks[joystick].axisComp[n].minRead = hidEvent.value; - if (hidEvent.value > ActiveJoysticks[joystick].axisComp[n].maxRead) - ActiveJoysticks[joystick].axisComp[n].maxRead = hidEvent.value; - - if (readScale != 0.0f) - hidEvent.value = (int)(((f32)((f32)hidEvent.value - (f32)ActiveJoysticks[joystick].axisComp[n].minRead) * deviceScale / readScale) + min); - - if (ActiveJoysticks[joystick].persistentData.JoystickEvent.Axis[n] != (s16)hidEvent.value) - found = true; - ActiveJoysticks[joystick].persistentData.JoystickEvent.Axis[n] = (s16)hidEvent.value; - } - } // axis check - - for (u32 n = 0; n < ActiveJoysticks[joystick].buttonComp.size(); n++) { - IOReturn result = kIOReturnSuccess; - IOHIDEventStruct hidEvent; - hidEvent.value = 0; - result = (*(ActiveJoysticks[joystick].interface))->getElementValue(ActiveJoysticks[joystick].interface, ActiveJoysticks[joystick].buttonComp[n].cookie, &hidEvent); - if (kIOReturnSuccess == result) { - if (hidEvent.value && !((ActiveJoysticks[joystick].persistentData.JoystickEvent.ButtonStates & (1 << n)) ? true : false)) - found = true; - else if (!hidEvent.value && ((ActiveJoysticks[joystick].persistentData.JoystickEvent.ButtonStates & (1 << n)) ? true : false)) - found = true; - - if (hidEvent.value) - ActiveJoysticks[joystick].persistentData.JoystickEvent.ButtonStates |= (1 << n); - else - ActiveJoysticks[joystick].persistentData.JoystickEvent.ButtonStates &= ~(1 << n); - } - } // button check - // still ToDo..will be done soon :) - /* - for (u32 n = 0; n < ActiveJoysticks[joystick].hatComp.size(); n++) - { - IOReturn result = kIOReturnSuccess; - IOHIDEventStruct hidEvent; - hidEvent.value = 0; - result = (*(ActiveJoysticks[joystick].interface))->getElementValue(ActiveJoysticks[joystick].interface, ActiveJoysticks[joystick].hatComp[n].cookie, &hidEvent); - if (kIOReturnSuccess == result) - { - if (ActiveJoysticks[joystick].persistentData.JoystickEvent.POV != hidEvent.value) - found = true; - ActiveJoysticks[joystick].persistentData.JoystickEvent.POV = hidEvent.value; - } - }//hat check - */ - } - - if (found) - postEventFromUser(ActiveJoysticks[joystick].persistentData); - } -#endif // _IRR_COMPILE_WITH_JOYSTICK_EVENTS_ -} - -#endif // _IRR_COMPILE_WITH_OSX_DEVICE_ diff --git a/irr/src/CIrrDeviceWin32.cpp b/irr/src/CIrrDeviceWin32.cpp deleted file mode 100644 index 63954de8ce..0000000000 --- a/irr/src/CIrrDeviceWin32.cpp +++ /dev/null @@ -1,1436 +0,0 @@ -// Copyright (C) 2002-2012 Nikolaus Gebhardt -// This file is part of the "Irrlicht Engine". -// For conditions of distribution and use, see copyright notice in irrlicht.h - -#ifdef _IRR_COMPILE_WITH_WINDOWS_DEVICE_ - -#if defined(__STRICT_ANSI__) -#error Compiling with __STRICT_ANSI__ not supported. g++ does set this when compiling with -std=c++11 or -std=c++0x. Use instead -std=gnu++11 or -std=gnu++0x. Or use -U__STRICT_ANSI__ to disable strict ansi. -#endif - -#include "CIrrDeviceWin32.h" -#include "IEventReceiver.h" -#include "os.h" - -#include "CTimer.h" -#include "irrString.h" -#include "COSOperator.h" -#include "dimension2d.h" -#include "IGUISpriteBank.h" -#include "IVideoDriver.h" -#include -#include "SExposedVideoData.h" - -#if defined(_IRR_COMPILE_WITH_JOYSTICK_EVENTS_) -#include -#include -#ifdef _IRR_COMPILE_WITH_DIRECTINPUT_JOYSTICK_ -#define DIRECTINPUT_VERSION 0x0800 -#include -#endif -#endif - -#if defined(_IRR_COMPILE_WITH_OGLES2_) -#include "CEGLManager.h" -#endif - -#if defined(_IRR_COMPILE_WITH_WGL_MANAGER_) -#include "CWGLManager.h" -#endif - -struct SJoystickWin32Control -{ - CIrrDeviceWin32 *Device; - -#if defined(_IRR_COMPILE_WITH_JOYSTICK_EVENTS_) && defined(_IRR_COMPILE_WITH_DIRECTINPUT_JOYSTICK_) - IDirectInput8 *DirectInputDevice; -#endif -#if defined(_IRR_COMPILE_WITH_JOYSTICK_EVENTS_) - struct JoystickInfo - { - u32 Index; -#ifdef _IRR_COMPILE_WITH_DIRECTINPUT_JOYSTICK_ - core::stringc Name; - GUID guid; - LPDIRECTINPUTDEVICE8 lpdijoy; - DIDEVCAPS devcaps; - u8 axisValid[8]; -#else - JOYCAPS Caps; -#endif - }; - core::array ActiveJoysticks; -#endif - - SJoystickWin32Control(CIrrDeviceWin32 *dev); - ~SJoystickWin32Control(); - -#if defined(_IRR_COMPILE_WITH_JOYSTICK_EVENTS_) && defined(_IRR_COMPILE_WITH_DIRECTINPUT_JOYSTICK_) - static BOOL CALLBACK EnumJoysticks(LPCDIDEVICEINSTANCE lpddi, LPVOID cp); - void directInputAddJoystick(LPCDIDEVICEINSTANCE lpddi); -#endif - - void pollJoysticks(); - bool activateJoysticks(core::array &joystickInfo); - core::stringc findJoystickName(int index, const JOYCAPS &caps) const; -}; - -SJoystickWin32Control::SJoystickWin32Control(CIrrDeviceWin32 *dev) : - Device(dev) -{ -#if defined(_IRR_COMPILE_WITH_JOYSTICK_EVENTS_) && defined(_IRR_COMPILE_WITH_DIRECTINPUT_JOYSTICK_) - DirectInputDevice = 0; - if (DI_OK != (DirectInput8Create(GetModuleHandle(NULL), DIRECTINPUT_VERSION, IID_IDirectInput8, (void **)&DirectInputDevice, NULL))) { - os::Printer::log("Could not create DirectInput8 Object", ELL_WARNING); - return; - } -#endif -} - -SJoystickWin32Control::~SJoystickWin32Control() -{ -#if defined(_IRR_COMPILE_WITH_JOYSTICK_EVENTS_) && defined(_IRR_COMPILE_WITH_DIRECTINPUT_JOYSTICK_) - for (u32 joystick = 0; joystick < ActiveJoysticks.size(); ++joystick) { - LPDIRECTINPUTDEVICE8 dev = ActiveJoysticks[joystick].lpdijoy; - if (dev) { - dev->Unacquire(); - dev->Release(); - } - } - - if (DirectInputDevice) - DirectInputDevice->Release(); -#endif -} - -#if defined(_IRR_COMPILE_WITH_JOYSTICK_EVENTS_) && defined(_IRR_COMPILE_WITH_DIRECTINPUT_JOYSTICK_) -BOOL CALLBACK SJoystickWin32Control::EnumJoysticks(LPCDIDEVICEINSTANCE lpddi, LPVOID cp) -{ - SJoystickWin32Control *p = (SJoystickWin32Control *)cp; - p->directInputAddJoystick(lpddi); - return DIENUM_CONTINUE; -} -void SJoystickWin32Control::directInputAddJoystick(LPCDIDEVICEINSTANCE lpddi) -{ - // Get the GUID of the joystuck - const GUID guid = lpddi->guidInstance; - - JoystickInfo activeJoystick; - activeJoystick.Index = ActiveJoysticks.size(); - activeJoystick.guid = guid; - activeJoystick.Name = lpddi->tszProductName; - if (FAILED(DirectInputDevice->CreateDevice(guid, &activeJoystick.lpdijoy, NULL))) { - os::Printer::log("Could not create DirectInput device", ELL_WARNING); - return; - } - - activeJoystick.devcaps.dwSize = sizeof(activeJoystick.devcaps); - if (FAILED(activeJoystick.lpdijoy->GetCapabilities(&activeJoystick.devcaps))) { - os::Printer::log("Could not create DirectInput device", ELL_WARNING); - return; - } - - if (FAILED(activeJoystick.lpdijoy->SetCooperativeLevel(Device->HWnd, DISCL_BACKGROUND | DISCL_EXCLUSIVE))) { - os::Printer::log("Could not set DirectInput device cooperative level", ELL_WARNING); - return; - } - - if (FAILED(activeJoystick.lpdijoy->SetDataFormat(&c_dfDIJoystick2))) { - os::Printer::log("Could not set DirectInput device data format", ELL_WARNING); - return; - } - - if (FAILED(activeJoystick.lpdijoy->Acquire())) { - os::Printer::log("Could not set DirectInput cooperative level", ELL_WARNING); - return; - } - - DIJOYSTATE2 info; - if (FAILED(activeJoystick.lpdijoy->GetDeviceState(sizeof(info), &info))) { - os::Printer::log("Could not read DirectInput device state", ELL_WARNING); - return; - } - - ZeroMemory(activeJoystick.axisValid, sizeof(activeJoystick.axisValid)); - activeJoystick.axisValid[0] = (info.lX != 0) ? 1 : 0; - activeJoystick.axisValid[1] = (info.lY != 0) ? 1 : 0; - activeJoystick.axisValid[2] = (info.lZ != 0) ? 1 : 0; - activeJoystick.axisValid[3] = (info.lRx != 0) ? 1 : 0; - activeJoystick.axisValid[4] = (info.lRy != 0) ? 1 : 0; - activeJoystick.axisValid[5] = (info.lRz != 0) ? 1 : 0; - - int caxis = 0; - for (u8 i = 0; i < 6; i++) { - if (activeJoystick.axisValid[i]) - caxis++; - } - - for (u8 i = 0; i < (activeJoystick.devcaps.dwAxes) - caxis; i++) { - if (i + caxis < 8) - activeJoystick.axisValid[i + caxis] = 1; - } - - ActiveJoysticks.push_back(activeJoystick); -} -#endif - -void SJoystickWin32Control::pollJoysticks() -{ -#if defined _IRR_COMPILE_WITH_JOYSTICK_EVENTS_ -#ifdef _IRR_COMPILE_WITH_DIRECTINPUT_JOYSTICK_ - if (0 == ActiveJoysticks.size()) - return; - - u32 joystick; - DIJOYSTATE2 info; - - for (joystick = 0; joystick < ActiveJoysticks.size(); ++joystick) { - // needs to be reset for each joystick - // request ALL values and POV as continuous if possible - - const DIDEVCAPS &caps = ActiveJoysticks[joystick].devcaps; - // if no POV is available don't ask for POV values - - if (!FAILED(ActiveJoysticks[joystick].lpdijoy->GetDeviceState(sizeof(info), &info))) { - SEvent event; - - event.EventType = EET_JOYSTICK_INPUT_EVENT; - event.JoystickEvent.Joystick = (u8)joystick; - - event.JoystickEvent.POV = (u16)info.rgdwPOV[0]; - // set to undefined if no POV value was returned or the value - // is out of range - if ((caps.dwPOVs == 0) || (event.JoystickEvent.POV > 35900)) - event.JoystickEvent.POV = 65535; - - for (int axis = 0; axis < SEvent::SJoystickEvent::NUMBER_OF_AXES; ++axis) - event.JoystickEvent.Axis[axis] = 0; - - u16 dxAxis = 0; - u16 irrAxis = 0; - - while (dxAxis < 6 && irrAxis < caps.dwAxes) { - bool axisFound = 0; - s32 axisValue = 0; - - switch (dxAxis) { - case 0: - axisValue = info.lX; - break; - case 1: - axisValue = info.lY; - break; - case 2: - axisValue = info.lZ; - break; - case 3: - axisValue = info.lRx; - break; - case 4: - axisValue = info.lRy; - break; - case 5: - axisValue = info.lRz; - break; - case 6: - axisValue = info.rglSlider[0]; - break; - case 7: - axisValue = info.rglSlider[1]; - break; - default: - break; - } - - if (ActiveJoysticks[joystick].axisValid[dxAxis] > 0) - axisFound = 1; - - if (axisFound) { - s32 val = axisValue - 32768; - - if (val < -32767) - val = -32767; - if (val > 32767) - val = 32767; - event.JoystickEvent.Axis[irrAxis] = (s16)(val); - irrAxis++; - } - - dxAxis++; - } - - u32 buttons = 0; - BYTE *bytebuttons = info.rgbButtons; - for (u16 i = 0; i < 32; i++) { - if (bytebuttons[i] > 0) { - buttons |= (1 << i); - } - } - event.JoystickEvent.ButtonStates = buttons; - - (void)Device->postEventFromUser(event); - } - } -#else - if (0 == ActiveJoysticks.size()) - return; - - u32 joystick; - JOYINFOEX info; - - for (joystick = 0; joystick < ActiveJoysticks.size(); ++joystick) { - // needs to be reset for each joystick - // request ALL values and POV as continuous if possible - info.dwSize = sizeof(info); - info.dwFlags = JOY_RETURNALL | JOY_RETURNPOVCTS; - const JOYCAPS &caps = ActiveJoysticks[joystick].Caps; - // if no POV is available don't ask for POV values - if (!(caps.wCaps & JOYCAPS_HASPOV)) - info.dwFlags &= ~(JOY_RETURNPOV | JOY_RETURNPOVCTS); - if (JOYERR_NOERROR == joyGetPosEx(ActiveJoysticks[joystick].Index, &info)) { - SEvent event; - - event.EventType = EET_JOYSTICK_INPUT_EVENT; - event.JoystickEvent.Joystick = (u8)joystick; - - event.JoystickEvent.POV = (u16)info.dwPOV; - // set to undefined if no POV value was returned or the value - // is out of range - if (!(info.dwFlags & JOY_RETURNPOV) || (event.JoystickEvent.POV > 35900)) - event.JoystickEvent.POV = 65535; - - for (int axis = 0; axis < SEvent::SJoystickEvent::NUMBER_OF_AXES; ++axis) - event.JoystickEvent.Axis[axis] = 0; - - event.JoystickEvent.ButtonStates = info.dwButtons; - - switch (caps.wNumAxes) { - default: - case 6: - event.JoystickEvent.Axis[SEvent::SJoystickEvent::AXIS_V] = - (s16)((65535 * (info.dwVpos - caps.wVmin)) / (caps.wVmax - caps.wVmin) - 32768); - - case 5: - event.JoystickEvent.Axis[SEvent::SJoystickEvent::AXIS_U] = - (s16)((65535 * (info.dwUpos - caps.wUmin)) / (caps.wUmax - caps.wUmin) - 32768); - - case 4: - event.JoystickEvent.Axis[SEvent::SJoystickEvent::AXIS_R] = - (s16)((65535 * (info.dwRpos - caps.wRmin)) / (caps.wRmax - caps.wRmin) - 32768); - - case 3: - event.JoystickEvent.Axis[SEvent::SJoystickEvent::AXIS_Z] = - (s16)((65535 * (info.dwZpos - caps.wZmin)) / (caps.wZmax - caps.wZmin) - 32768); - - case 2: - event.JoystickEvent.Axis[SEvent::SJoystickEvent::AXIS_Y] = - (s16)((65535 * (info.dwYpos - caps.wYmin)) / (caps.wYmax - caps.wYmin) - 32768); - - case 1: - event.JoystickEvent.Axis[SEvent::SJoystickEvent::AXIS_X] = - (s16)((65535 * (info.dwXpos - caps.wXmin)) / (caps.wXmax - caps.wXmin) - 32768); - } - - (void)Device->postEventFromUser(event); - } - } -#endif -#endif // _IRR_COMPILE_WITH_JOYSTICK_EVENTS_ -} - -/** This function is ported from SDL and released under zlib-license: - * Copyright (C) 1997-2014 Sam Lantinga */ -core::stringc SJoystickWin32Control::findJoystickName(int index, const JOYCAPS &caps) const -{ -#if defined _IRR_COMPILE_WITH_JOYSTICK_EVENTS_ - - // As a default use the name given in the joystick structure. - // It is always the same name, independent of joystick. - core::stringc result(caps.szPname); - - core::stringc key = core::stringc(REGSTR_PATH_JOYCONFIG) + "\\" + caps.szRegKey + "\\" + REGSTR_KEY_JOYCURR; - HKEY hTopKey = HKEY_LOCAL_MACHINE; - HKEY hKey; - long regresult = RegOpenKeyExA(hTopKey, key.c_str(), 0, KEY_READ, &hKey); - if (regresult != ERROR_SUCCESS) { - hTopKey = HKEY_CURRENT_USER; - regresult = RegOpenKeyExA(hTopKey, key.c_str(), 0, KEY_READ, &hKey); - } - if (regresult != ERROR_SUCCESS) - return result; - - /* find the registry key name for the joystick's properties */ - char regname[256]; - DWORD regsize = sizeof(regname); - core::stringc regvalue = core::stringc("Joystick") + core::stringc(index + 1) + REGSTR_VAL_JOYOEMNAME; - regresult = RegQueryValueExA(hKey, regvalue.c_str(), 0, 0, (LPBYTE)regname, ®size); - RegCloseKey(hKey); - if (regresult != ERROR_SUCCESS) - return result; - - /* open that registry key */ - core::stringc regkey = core::stringc(REGSTR_PATH_JOYOEM) + "\\" + regname; - regresult = RegOpenKeyExA(hTopKey, regkey.c_str(), 0, KEY_READ, &hKey); - if (regresult != ERROR_SUCCESS) - return result; - - /* find the size for the OEM name text */ - regsize = sizeof(regvalue); - regresult = RegQueryValueEx(hKey, REGSTR_VAL_JOYOEMNAME, 0, 0, - NULL, ®size); - if (regresult == ERROR_SUCCESS) { - char *name; - /* allocate enough memory for the OEM name text ... */ - name = new char[regsize]; - if (name) { - /* ... and read it from the registry */ - regresult = RegQueryValueEx(hKey, REGSTR_VAL_JOYOEMNAME, 0, 0, - (LPBYTE)name, ®size); - result = name; - } - delete[] name; - } - RegCloseKey(hKey); - - return result; -#endif - return ""; -} - -bool SJoystickWin32Control::activateJoysticks(core::array &joystickInfo) -{ -#if defined _IRR_COMPILE_WITH_JOYSTICK_EVENTS_ - joystickInfo.clear(); - ActiveJoysticks.clear(); -#ifdef _IRR_COMPILE_WITH_DIRECTINPUT_JOYSTICK_ - if (!DirectInputDevice || (DirectInputDevice->EnumDevices(DI8DEVCLASS_GAMECTRL, SJoystickWin32Control::EnumJoysticks, this, DIEDFL_ATTACHEDONLY))) { - os::Printer::log("Could not enum DirectInput8 controllers", ELL_WARNING); - return false; - } - - for (u32 joystick = 0; joystick < ActiveJoysticks.size(); ++joystick) { - JoystickInfo &activeJoystick = ActiveJoysticks[joystick]; - SJoystickInfo info; - info.Axes = activeJoystick.devcaps.dwAxes; - info.Buttons = activeJoystick.devcaps.dwButtons; - info.Name = activeJoystick.Name; - info.PovHat = (activeJoystick.devcaps.dwPOVs != 0) - ? SJoystickInfo::POV_HAT_PRESENT - : SJoystickInfo::POV_HAT_ABSENT; - joystickInfo.push_back(info); - } - return true; -#else - const u32 numberOfJoysticks = ::joyGetNumDevs(); - JOYINFOEX info; - info.dwSize = sizeof(info); - info.dwFlags = JOY_RETURNALL; - - JoystickInfo activeJoystick; - SJoystickInfo returnInfo; - - joystickInfo.reallocate(numberOfJoysticks); - ActiveJoysticks.reallocate(numberOfJoysticks); - - u32 joystick = 0; - for (; joystick < numberOfJoysticks; ++joystick) { - if (JOYERR_NOERROR == joyGetPosEx(joystick, &info) && - JOYERR_NOERROR == joyGetDevCaps(joystick, - &activeJoystick.Caps, - sizeof(activeJoystick.Caps))) { - activeJoystick.Index = joystick; - ActiveJoysticks.push_back(activeJoystick); - - returnInfo.Joystick = (u8)joystick; - returnInfo.Axes = activeJoystick.Caps.wNumAxes; - returnInfo.Buttons = activeJoystick.Caps.wNumButtons; - returnInfo.Name = findJoystickName(joystick, activeJoystick.Caps); - returnInfo.PovHat = ((activeJoystick.Caps.wCaps & JOYCAPS_HASPOV) == JOYCAPS_HASPOV) - ? SJoystickInfo::POV_HAT_PRESENT - : SJoystickInfo::POV_HAT_ABSENT; - - joystickInfo.push_back(returnInfo); - } - } - - for (joystick = 0; joystick < joystickInfo.size(); ++joystick) { - char logString[256]; - snprintf_irr(logString, sizeof(logString), "Found joystick %d, %d axes, %d buttons '%s'", - joystick, joystickInfo[joystick].Axes, - joystickInfo[joystick].Buttons, joystickInfo[joystick].Name.c_str()); - os::Printer::log(logString, ELL_INFORMATION); - } - - return true; -#endif -#else - return false; -#endif // _IRR_COMPILE_WITH_JOYSTICK_EVENTS_ -} - -namespace -{ -struct SEnvMapper -{ - HWND hWnd; - CIrrDeviceWin32 *irrDev; -}; -// NOTE: This is global. We can have more than one Irrlicht Device at same time. -core::array EnvMap; - -HKL KEYBOARD_INPUT_HKL = 0; -} - -CIrrDeviceWin32 *getDeviceFromHWnd(HWND hWnd) -{ - const u32 end = EnvMap.size(); - for (u32 i = 0; i < end; ++i) { - const SEnvMapper &env = EnvMap[i]; - if (env.hWnd == hWnd) - return env.irrDev; - } - - return 0; -} - -LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) -{ -#ifndef WHEEL_DELTA -#define WHEEL_DELTA 120 -#endif - - CIrrDeviceWin32 *dev = 0; - SEvent event; - - static s32 ClickCount = 0; - if (GetCapture() != hWnd && ClickCount > 0) - ClickCount = 0; - - struct messageMap - { - s32 group; - UINT winMessage; - s32 irrMessage; - }; - - static messageMap mouseMap[] = { - {0, WM_LBUTTONDOWN, EMIE_LMOUSE_PRESSED_DOWN}, - {1, WM_LBUTTONUP, EMIE_LMOUSE_LEFT_UP}, - {0, WM_RBUTTONDOWN, EMIE_RMOUSE_PRESSED_DOWN}, - {1, WM_RBUTTONUP, EMIE_RMOUSE_LEFT_UP}, - {0, WM_MBUTTONDOWN, EMIE_MMOUSE_PRESSED_DOWN}, - {1, WM_MBUTTONUP, EMIE_MMOUSE_LEFT_UP}, - {2, WM_MOUSEMOVE, EMIE_MOUSE_MOVED}, - {3, WM_MOUSEWHEEL, EMIE_MOUSE_WHEEL}, - {-1, 0, 0}, - }; - - // handle grouped events - messageMap *m = mouseMap; - while (m->group >= 0 && m->winMessage != message) - m += 1; - - if (m->group >= 0) { - if (m->group == 0) { // down - ClickCount++; - SetCapture(hWnd); - } else if (m->group == 1) { // up - ClickCount--; - if (ClickCount < 1) { - ClickCount = 0; - ReleaseCapture(); - } - } - - event.EventType = EET_MOUSE_INPUT_EVENT; - event.MouseInput.Event = (EMOUSE_INPUT_EVENT)m->irrMessage; - event.MouseInput.X = (short)LOWORD(lParam); - event.MouseInput.Y = (short)HIWORD(lParam); - event.MouseInput.Shift = ((LOWORD(wParam) & MK_SHIFT) != 0); - event.MouseInput.Control = ((LOWORD(wParam) & MK_CONTROL) != 0); - // left and right mouse buttons - event.MouseInput.ButtonStates = wParam & (MK_LBUTTON | MK_RBUTTON); - // middle and extra buttons - if (wParam & MK_MBUTTON) - event.MouseInput.ButtonStates |= EMBSM_MIDDLE; - if (wParam & MK_XBUTTON1) - event.MouseInput.ButtonStates |= EMBSM_EXTRA1; - if (wParam & MK_XBUTTON2) - event.MouseInput.ButtonStates |= EMBSM_EXTRA2; - event.MouseInput.Wheel = 0.f; - - // wheel - if (m->group == 3) { - POINT p; // fixed by jox - p.x = 0; - p.y = 0; - ClientToScreen(hWnd, &p); - event.MouseInput.X -= p.x; - event.MouseInput.Y -= p.y; - event.MouseInput.Wheel = ((f32)((short)HIWORD(wParam))) / (f32)WHEEL_DELTA; - } - - dev = getDeviceFromHWnd(hWnd); - if (dev) { - dev->postEventFromUser(event); - - if (event.MouseInput.Event >= EMIE_LMOUSE_PRESSED_DOWN && event.MouseInput.Event <= EMIE_MMOUSE_PRESSED_DOWN) { - u32 clicks = dev->checkSuccessiveClicks(event.MouseInput.X, event.MouseInput.Y, event.MouseInput.Event); - if (clicks == 2) { - event.MouseInput.Event = (EMOUSE_INPUT_EVENT)(EMIE_LMOUSE_DOUBLE_CLICK + event.MouseInput.Event - EMIE_LMOUSE_PRESSED_DOWN); - dev->postEventFromUser(event); - } else if (clicks == 3) { - event.MouseInput.Event = (EMOUSE_INPUT_EVENT)(EMIE_LMOUSE_TRIPLE_CLICK + event.MouseInput.Event - EMIE_LMOUSE_PRESSED_DOWN); - dev->postEventFromUser(event); - } - } - } - return 0; - } - - switch (message) { - case WM_PAINT: { - PAINTSTRUCT ps; - BeginPaint(hWnd, &ps); - EndPaint(hWnd, &ps); - } - return 0; - - case WM_ERASEBKGND: - return 0; - - case WM_SYSKEYDOWN: - case WM_SYSKEYUP: - case WM_KEYDOWN: - case WM_KEYUP: { - BYTE allKeys[256]; - - event.EventType = EET_KEY_INPUT_EVENT; - event.KeyInput.Key = (EKEY_CODE)wParam; - event.KeyInput.PressedDown = (message == WM_KEYDOWN || message == WM_SYSKEYDOWN); - - if (event.KeyInput.Key == KEY_SHIFT) { - event.KeyInput.Key = (EKEY_CODE)MapVirtualKey(((lParam >> 16) & 255), MAPVK_VSC_TO_VK_EX); - } - if (event.KeyInput.Key == KEY_CONTROL) { - event.KeyInput.Key = (EKEY_CODE)MapVirtualKey(((lParam >> 16) & 255), MAPVK_VSC_TO_VK_EX); - // some keyboards will just return LEFT for both - left and right keys. So also check extend bit. - if (lParam & 0x1000000) - event.KeyInput.Key = KEY_RCONTROL; - } - if (event.KeyInput.Key == KEY_MENU) { - event.KeyInput.Key = (EKEY_CODE)MapVirtualKey(((lParam >> 16) & 255), MAPVK_VSC_TO_VK_EX); - if (lParam & 0x1000000) - event.KeyInput.Key = KEY_RMENU; - } - - GetKeyboardState(allKeys); - - event.KeyInput.Shift = ((allKeys[VK_SHIFT] & 0x80) != 0); - event.KeyInput.Control = ((allKeys[VK_CONTROL] & 0x80) != 0); - - // Handle unicode and deadkeys - WCHAR keyChars[2]; - UINT scanCode = HIWORD(lParam); - int conversionResult = ToUnicodeEx(static_cast(wParam), scanCode, allKeys, keyChars, 2, 0, KEYBOARD_INPUT_HKL); - if (conversionResult == 1) - event.KeyInput.Char = keyChars[0]; - else - event.KeyInput.Char = 0; - - // allow composing characters like '@' with Alt Gr on non-US keyboards - if ((allKeys[VK_MENU] & 0x80) != 0) - event.KeyInput.Control = 0; - - dev = getDeviceFromHWnd(hWnd); - if (dev) - dev->postEventFromUser(event); - - if (message == WM_SYSKEYDOWN || message == WM_SYSKEYUP) - return DefWindowProcW(hWnd, message, wParam, lParam); - else - return 0; - } - - case WM_SIZE: { - // resize - dev = getDeviceFromHWnd(hWnd); - if (dev) - dev->OnResized(); - } - return 0; - - case WM_DESTROY: - PostQuitMessage(0); - return 0; - - case WM_SYSCOMMAND: - // prevent screensaver or monitor powersave mode from starting - if ((wParam & 0xFFF0) == SC_SCREENSAVE || - (wParam & 0xFFF0) == SC_MONITORPOWER || - (wParam & 0xFFF0) == SC_KEYMENU) - return 0; - - break; - - case WM_USER: - event.EventType = EET_USER_EVENT; - event.UserEvent.UserData1 = static_cast(wParam); - event.UserEvent.UserData2 = static_cast(lParam); - dev = getDeviceFromHWnd(hWnd); - - if (dev) - dev->postEventFromUser(event); - - return 0; - - case WM_SETCURSOR: - // because Windows forgot about that in the meantime - dev = getDeviceFromHWnd(hWnd); - if (dev) { - dev->getCursorControl()->setActiveIcon(dev->getCursorControl()->getActiveIcon()); - dev->getCursorControl()->setVisible(dev->getCursorControl()->isVisible()); - } - break; - - case WM_INPUTLANGCHANGE: - // get the new codepage used for keyboard input - KEYBOARD_INPUT_HKL = GetKeyboardLayout(0); - return 0; - } - return DefWindowProcW(hWnd, message, wParam, lParam); -} - -//! constructor -CIrrDeviceWin32::CIrrDeviceWin32(const SIrrlichtCreationParameters ¶ms) : - CIrrDeviceStub(params), HWnd(0), Resized(false), - ExternalWindow(false), Win32CursorControl(0), JoyControl(0), - WindowMaximized(params.WindowMaximized) -{ - // get windows version and create OS operator - core::stringc winversion; - getWindowsVersion(winversion); - Operator = new COSOperator(winversion); - os::Printer::log(winversion.c_str(), ELL_INFORMATION); - - // get handle to exe file - HINSTANCE hInstance = GetModuleHandle(0); - - // create the window if we need to and we do not use the null device - if (!CreationParams.WindowId && CreationParams.DriverType != video::EDT_NULL) { - const wchar_t *ClassName = L"CIrrDeviceWin32"; - - // Register Class - WNDCLASSEXW wcex; - wcex.cbSize = sizeof(WNDCLASSEXW); - wcex.style = CS_HREDRAW | CS_VREDRAW; - wcex.lpfnWndProc = WndProc; - wcex.cbClsExtra = 0; - wcex.cbWndExtra = 0; - wcex.hInstance = hInstance; - wcex.hIcon = NULL; - wcex.hCursor = 0; // LoadCursor(NULL, IDC_ARROW); - wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1); - wcex.lpszMenuName = 0; - wcex.lpszClassName = ClassName; - wcex.hIconSm = 0; - - RegisterClassExW(&wcex); - - // calculate client size - - RECT clientSize; - clientSize.top = 0; - clientSize.left = 0; - clientSize.right = CreationParams.WindowSize.Width; - clientSize.bottom = CreationParams.WindowSize.Height; - - DWORD style = getWindowStyle(CreationParams.Fullscreen, CreationParams.WindowResizable > 0 ? true : false); - AdjustWindowRect(&clientSize, style, FALSE); - - const s32 realWidth = clientSize.right - clientSize.left; - const s32 realHeight = clientSize.bottom - clientSize.top; - - s32 windowLeft = (CreationParams.WindowPosition.X == -1 ? (GetSystemMetrics(SM_CXSCREEN) - realWidth) / 2 : CreationParams.WindowPosition.X); - s32 windowTop = (CreationParams.WindowPosition.Y == -1 ? (GetSystemMetrics(SM_CYSCREEN) - realHeight) / 2 : CreationParams.WindowPosition.Y); - - if (windowLeft < 0) - windowLeft = 0; - if (windowTop < 0) - windowTop = 0; // make sure window menus are in screen on creation - - if (CreationParams.Fullscreen) { - windowLeft = 0; - windowTop = 0; - } - - // create window - HWnd = CreateWindowW(ClassName, L"", style, windowLeft, windowTop, - realWidth, realHeight, NULL, NULL, hInstance, NULL); - if (!HWnd) { - os::Printer::log("Window could not be created.", ELL_ERROR); - } - - CreationParams.WindowId = HWnd; - // CreationParams.WindowSize.Width = realWidth; - // CreationParams.WindowSize.Height = realHeight; - - ShowWindow(HWnd, SW_SHOWNORMAL); - UpdateWindow(HWnd); - - // fix ugly ATI driver bugs. Thanks to ariaci - MoveWindow(HWnd, windowLeft, windowTop, realWidth, realHeight, TRUE); - - // make sure everything gets updated to the real sizes - Resized = true; - } else if (CreationParams.WindowId) { - // attach external window - HWnd = static_cast(CreationParams.WindowId); - RECT r; - GetWindowRect(HWnd, &r); - CreationParams.WindowSize.Width = r.right - r.left; - CreationParams.WindowSize.Height = r.bottom - r.top; - CreationParams.Fullscreen = false; - ExternalWindow = true; - } - - // create cursor control - - Win32CursorControl = new CCursorControl(this, CreationParams.WindowSize, HWnd, CreationParams.Fullscreen); - CursorControl = Win32CursorControl; - JoyControl = new SJoystickWin32Control(this); - - // initialize doubleclicks with system values - MouseMultiClicks.DoubleClickTime = GetDoubleClickTime(); - - // create driver - - createDriver(); - - if (VideoDriver) - createGUIAndScene(); - - // register environment - - SEnvMapper em; - em.irrDev = this; - em.hWnd = HWnd; - EnvMap.push_back(em); - - // set this as active window - if (!ExternalWindow) { - SetActiveWindow(HWnd); - SetForegroundWindow(HWnd); - } - - KEYBOARD_INPUT_HKL = GetKeyboardLayout(0); - - // inform driver about the window size etc. - resizeIfNecessary(); - - if (params.WindowMaximized) - maximizeWindow(); -} - -//! destructor -CIrrDeviceWin32::~CIrrDeviceWin32() -{ - delete JoyControl; - - // unregister environment - for (u32 i = 0; i < EnvMap.size(); ++i) { - if (EnvMap[i].hWnd == HWnd) { - EnvMap.erase(i); - break; - } - } -} - -//! create the driver -void CIrrDeviceWin32::createDriver() -{ - switch (CreationParams.DriverType) { - case video::EDT_OPENGL: -#ifdef _IRR_COMPILE_WITH_OPENGL_ - switchToFullScreen(); - - ContextManager = new video::CWGLManager(); - ContextManager->initialize(CreationParams, video::SExposedVideoData(HWnd)); -#endif - VideoDriver = video::createOpenGLDriver(CreationParams, FileSystem, ContextManager); - - if (!VideoDriver) - os::Printer::log("Could not create OpenGL driver.", ELL_ERROR); - break; - case video::EDT_OPENGL3: -#ifdef ENABLE_OPENGL3 - switchToFullScreen(); - - ContextManager = new video::CWGLManager(); - ContextManager->initialize(CreationParams, video::SExposedVideoData(HWnd)); -#endif - VideoDriver = video::createOpenGL3Driver(CreationParams, FileSystem, ContextManager); - - if (!VideoDriver) - os::Printer::log("Could not create OpenGL 3 driver.", ELL_ERROR); - break; - case video::EDT_OGLES2: -#ifdef _IRR_COMPILE_WITH_OGLES2_ - switchToFullScreen(); - - ContextManager = new video::CEGLManager(); - ContextManager->initialize(CreationParams, video::SExposedVideoData(HWnd)); -#endif - VideoDriver = video::createOGLES2Driver(CreationParams, FileSystem, ContextManager); - - if (!VideoDriver) - os::Printer::log("Could not create OpenGL-ES2 driver.", ELL_ERROR); - break; - case video::EDT_WEBGL1: - os::Printer::log("WebGL1 driver not supported on Win32 device.", ELL_ERROR); - break; - case video::EDT_NULL: - VideoDriver = video::createNullDriver(FileSystem, CreationParams.WindowSize); - break; - default: - os::Printer::log("Unable to create video driver of unknown type.", ELL_ERROR); - break; - } -} - -//! runs the device. Returns false if device wants to be deleted -bool CIrrDeviceWin32::run() -{ - os::Timer::tick(); - - static_cast(CursorControl)->update(); - - handleSystemMessages(); - - if (!Close) - resizeIfNecessary(); - - if (!Close && JoyControl) - JoyControl->pollJoysticks(); - - return !Close; -} - -//! Pause the current process for the minimum time allowed only to allow other processes to execute -void CIrrDeviceWin32::yield() -{ - Sleep(0); -} - -//! Pause execution and let other processes to run for a specified amount of time. -void CIrrDeviceWin32::sleep(u32 timeMs, bool pauseTimer) -{ - const bool wasStopped = Timer ? Timer->isStopped() : true; - if (pauseTimer && !wasStopped) - Timer->stop(); - - Sleep(timeMs); - - if (pauseTimer && !wasStopped) - Timer->start(); -} - -void CIrrDeviceWin32::resizeIfNecessary() -{ - if (!Resized || !getVideoDriver()) - return; - - RECT r; - GetClientRect(HWnd, &r); - - char tmp[255]; - - if (r.right < 2 || r.bottom < 2) { - snprintf_irr(tmp, sizeof(tmp), "Ignoring resize operation to (%ld %ld)", r.right, r.bottom); - os::Printer::log(tmp); - } else { - snprintf_irr(tmp, sizeof(tmp), "Resizing window (%ld %ld)", r.right, r.bottom); - os::Printer::log(tmp); - - getVideoDriver()->OnResize(core::dimension2du((u32)r.right, (u32)r.bottom)); - getWin32CursorControl()->OnResize(getVideoDriver()->getScreenSize()); - } - - Resized = false; -} - -DWORD CIrrDeviceWin32::getWindowStyle(bool fullscreen, bool resizable) const -{ - if (fullscreen) - return WS_POPUP; - - if (resizable) - return WS_THICKFRAME | WS_SYSMENU | WS_CAPTION | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | WS_MINIMIZEBOX | WS_MAXIMIZEBOX; - - return WS_BORDER | WS_SYSMENU | WS_CAPTION | WS_CLIPCHILDREN | WS_CLIPSIBLINGS; -} - -//! sets the caption of the window -void CIrrDeviceWin32::setWindowCaption(const wchar_t *text) -{ - // We use SendMessage instead of SetText to ensure proper - // function even in cases where the HWND was created in a different thread - DWORD_PTR dwResult; - SendMessageTimeoutW(HWnd, WM_SETTEXT, 0, - reinterpret_cast(text), - SMTO_ABORTIFHUNG, 2000, &dwResult); -} - -//! Sets the window icon. -bool CIrrDeviceWin32::setWindowIcon(const video::IImage *img) -{ - // Ignore the img, instead load the ICON from resource file - // (This is minetest-specific!) - const HICON hicon = LoadIcon(GetModuleHandle(NULL), - MAKEINTRESOURCE(130) // The ID of the ICON defined in - // winresource.rc - ); - - if (hicon) { - SendMessage(HWnd, WM_SETICON, ICON_BIG, reinterpret_cast(hicon)); - SendMessage(HWnd, WM_SETICON, ICON_SMALL, - reinterpret_cast(hicon)); - return true; - } - return false; -} - -//! notifies the device that it should close itself -void CIrrDeviceWin32::closeDevice() -{ - if (!ExternalWindow) { - MSG msg; - PeekMessage(&msg, NULL, WM_QUIT, WM_QUIT, PM_REMOVE); - PostQuitMessage(0); - PeekMessage(&msg, NULL, WM_QUIT, WM_QUIT, PM_REMOVE); - DestroyWindow(HWnd); - const wchar_t *ClassName = L"CIrrDeviceWin32"; - HINSTANCE hInstance = GetModuleHandle(0); - UnregisterClassW(ClassName, hInstance); - } - Close = true; -} - -//! returns if window is active. if not, nothing needs to be drawn -bool CIrrDeviceWin32::isWindowActive() const -{ - return (GetActiveWindow() == HWnd); -} - -//! returns if window has focus -bool CIrrDeviceWin32::isWindowFocused() const -{ - bool ret = (GetFocus() == HWnd); - return ret; -} - -//! returns if window is minimized -bool CIrrDeviceWin32::isWindowMinimized() const -{ - WINDOWPLACEMENT plc; - plc.length = sizeof(WINDOWPLACEMENT); - bool ret = false; - if (GetWindowPlacement(HWnd, &plc)) - ret = plc.showCmd == SW_SHOWMINIMIZED; - return ret; -} - -//! returns last state from maximizeWindow() and restoreWindow() -bool CIrrDeviceWin32::isWindowMaximized() const -{ - return WindowMaximized; -} - -//! switches to fullscreen -bool CIrrDeviceWin32::switchToFullScreen() -{ - if (!CreationParams.Fullscreen) - return true; - - // No border, title bar, etc. is already set up through getWindowStyle() - // We only set the window size to match the monitor. - - MONITORINFO mi; - mi.cbSize = sizeof(mi); - if (GetMonitorInfo(MonitorFromWindow(HWnd, MONITOR_DEFAULTTOPRIMARY), &mi)) { - UINT flags = SWP_NOCOPYBITS | SWP_NOOWNERZORDER | SWP_FRAMECHANGED; - SetWindowPos(HWnd, HWND_TOP, mi.rcMonitor.left, mi.rcMonitor.top, - mi.rcMonitor.right - mi.rcMonitor.left, - mi.rcMonitor.bottom - mi.rcMonitor.top, flags); - } else { - CreationParams.Fullscreen = false; - } - - return CreationParams.Fullscreen; -} - -//! returns the win32 cursor control -CIrrDeviceWin32::CCursorControl *CIrrDeviceWin32::getWin32CursorControl() -{ - return Win32CursorControl; -} - -void CIrrDeviceWin32::getWindowsVersion(core::stringc &out) -{ - OSVERSIONINFO osvi; - - ZeroMemory(&osvi, sizeof(OSVERSIONINFO)); - osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); - GetVersionEx(&osvi); - - char tmp[255]; - snprintf(tmp, sizeof(tmp), "Microsoft Windows %lu.%lu %s", osvi.dwMajorVersion, osvi.dwMinorVersion, osvi.szCSDVersion); - out.append(tmp); -} - -//! Notifies the device, that it has been resized -void CIrrDeviceWin32::OnResized() -{ - Resized = true; -} - -//! Resize the render window. -void CIrrDeviceWin32::setWindowSize(const core::dimension2d &size) -{ - if (ExternalWindow || !getVideoDriver() || CreationParams.Fullscreen) - return; - - // get size of the window for the give size of the client area - DWORD style = static_cast(GetWindowLongPtr(HWnd, GWL_STYLE)); - DWORD exStyle = static_cast(GetWindowLongPtr(HWnd, GWL_EXSTYLE)); - RECT clientSize; - clientSize.top = 0; - clientSize.left = 0; - clientSize.right = size.Width; - clientSize.bottom = size.Height; - AdjustWindowRectEx(&clientSize, style, false, exStyle); - const s32 realWidth = clientSize.right - clientSize.left; - const s32 realHeight = clientSize.bottom - clientSize.top; - - UINT flags = SWP_NOACTIVATE | SWP_NOCOPYBITS | SWP_NOMOVE | SWP_NOOWNERZORDER | SWP_NOZORDER; - SetWindowPos(HWnd, HWND_TOP, 0, 0, realWidth, realHeight, flags); -} - -//! Sets if the window should be resizable in windowed mode. -void CIrrDeviceWin32::setResizable(bool resize) -{ - if (ExternalWindow || !getVideoDriver() || CreationParams.Fullscreen) - return; - - LONG_PTR style = (LONG_PTR)getWindowStyle(false, resize); - if (!SetWindowLongPtr(HWnd, GWL_STYLE, style)) - os::Printer::log("Could not change window style."); - - RECT clientSize; - clientSize.top = 0; - clientSize.left = 0; - clientSize.right = getVideoDriver()->getScreenSize().Width; - clientSize.bottom = getVideoDriver()->getScreenSize().Height; - - AdjustWindowRect(&clientSize, static_cast(style), FALSE); - - const s32 realWidth = clientSize.right - clientSize.left; - const s32 realHeight = clientSize.bottom - clientSize.top; - - const s32 windowLeft = (GetSystemMetrics(SM_CXSCREEN) - realWidth) / 2; - const s32 windowTop = (GetSystemMetrics(SM_CYSCREEN) - realHeight) / 2; - - SetWindowPos(HWnd, HWND_TOP, windowLeft, windowTop, realWidth, realHeight, - SWP_FRAMECHANGED | SWP_NOMOVE | SWP_SHOWWINDOW); - - static_cast(CursorControl)->updateBorderSize(CreationParams.Fullscreen, resize); -} - -//! Minimizes the window. -void CIrrDeviceWin32::minimizeWindow() -{ - WINDOWPLACEMENT wndpl; - wndpl.length = sizeof(WINDOWPLACEMENT); - GetWindowPlacement(HWnd, &wndpl); - wndpl.showCmd = SW_SHOWMINNOACTIVE; - SetWindowPlacement(HWnd, &wndpl); -} - -//! Maximizes the window. -void CIrrDeviceWin32::maximizeWindow() -{ - WINDOWPLACEMENT wndpl; - wndpl.length = sizeof(WINDOWPLACEMENT); - GetWindowPlacement(HWnd, &wndpl); - wndpl.showCmd = SW_SHOWMAXIMIZED; - SetWindowPlacement(HWnd, &wndpl); - - WindowMaximized = true; -} - -//! Restores the window to its original size. -void CIrrDeviceWin32::restoreWindow() -{ - WINDOWPLACEMENT wndpl; - wndpl.length = sizeof(WINDOWPLACEMENT); - GetWindowPlacement(HWnd, &wndpl); - wndpl.showCmd = SW_SHOWNORMAL; - SetWindowPlacement(HWnd, &wndpl); - - WindowMaximized = false; -} - -core::position2di CIrrDeviceWin32::getWindowPosition() -{ - WINDOWPLACEMENT wndpl; - wndpl.length = sizeof(WINDOWPLACEMENT); - if (GetWindowPlacement(HWnd, &wndpl)) { - return core::position2di((int)wndpl.rcNormalPosition.left, - (int)wndpl.rcNormalPosition.top); - } else { - // No reason for this to happen - os::Printer::log("Failed to retrieve window location", ELL_ERROR); - return core::position2di(-1, -1); - } -} - -bool CIrrDeviceWin32::activateJoysticks(core::array &joystickInfo) -{ - if (JoyControl) - return JoyControl->activateJoysticks(joystickInfo); - else - return false; -} - -//! Process system events -void CIrrDeviceWin32::handleSystemMessages() -{ - MSG msg; - - while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) { - if (ExternalWindow && msg.hwnd == HWnd) { - if (msg.hwnd == HWnd) { - WndProc(HWnd, msg.message, msg.wParam, msg.lParam); - } else { - TranslateMessage(&msg); - DispatchMessage(&msg); - } - } else { - // No message translation because we don't use WM_CHAR and it would conflict with our - // deadkey handling. - DispatchMessage(&msg); - } - - if (msg.message == WM_QUIT) - Close = true; - } -} - -//! Remove all messages pending in the system message loop -void CIrrDeviceWin32::clearSystemMessages() -{ - MSG msg; - while (PeekMessage(&msg, NULL, WM_KEYFIRST, WM_KEYLAST, PM_REMOVE)) { - } - while (PeekMessage(&msg, NULL, WM_MOUSEFIRST, WM_MOUSELAST, PM_REMOVE)) { - } -} - -//! Get the display density in dots per inch. -float CIrrDeviceWin32::getDisplayDensity() const -{ - HDC hdc = GetDC(HWnd); - float dpi = GetDeviceCaps(hdc, LOGPIXELSX); - ReleaseDC(HWnd, hdc); - return dpi; -} - -// Convert an Irrlicht texture to a Windows cursor -// Based on http://www.codeguru.com/cpp/w-p/win32/cursors/article.php/c4529/ -HCURSOR CIrrDeviceWin32::TextureToCursor(HWND hwnd, video::ITexture *tex, const core::rect &sourceRect, const core::position2d &hotspot) -{ - // - // create the bitmaps needed for cursors from the texture - - HDC dc = GetDC(hwnd); - HDC andDc = CreateCompatibleDC(dc); - HDC xorDc = CreateCompatibleDC(dc); - HBITMAP andBitmap = CreateCompatibleBitmap(dc, sourceRect.getWidth(), sourceRect.getHeight()); - HBITMAP xorBitmap = CreateCompatibleBitmap(dc, sourceRect.getWidth(), sourceRect.getHeight()); - - HBITMAP oldAndBitmap = (HBITMAP)SelectObject(andDc, andBitmap); - HBITMAP oldXorBitmap = (HBITMAP)SelectObject(xorDc, xorBitmap); - - video::ECOLOR_FORMAT format = tex->getColorFormat(); - u32 bytesPerPixel = video::IImage::getBitsPerPixelFromFormat(format) / 8; - u32 bytesLeftGap = sourceRect.UpperLeftCorner.X * bytesPerPixel; - u32 bytesRightGap = tex->getPitch() - sourceRect.LowerRightCorner.X * bytesPerPixel; - const u8 *data = (const u8 *)tex->lock(video::ETLM_READ_ONLY, 0); - data += sourceRect.UpperLeftCorner.Y * tex->getPitch(); - for (s32 y = 0; y < sourceRect.getHeight(); ++y) { - data += bytesLeftGap; - for (s32 x = 0; x < sourceRect.getWidth(); ++x) { - video::SColor pixelCol; - pixelCol.setData((const void *)data, format); - data += bytesPerPixel; - - if (pixelCol.getAlpha() == 0) { // transparent - SetPixel(andDc, x, y, RGB(255, 255, 255)); - SetPixel(xorDc, x, y, RGB(0, 0, 0)); - } else // color - { - SetPixel(andDc, x, y, RGB(0, 0, 0)); - SetPixel(xorDc, x, y, RGB(pixelCol.getRed(), pixelCol.getGreen(), pixelCol.getBlue())); - } - } - data += bytesRightGap; - } - tex->unlock(); - - SelectObject(andDc, oldAndBitmap); - SelectObject(xorDc, oldXorBitmap); - - DeleteDC(xorDc); - DeleteDC(andDc); - - ReleaseDC(hwnd, dc); - - // create the cursor - - ICONINFO iconinfo; - iconinfo.fIcon = false; // type is cursor not icon - iconinfo.xHotspot = hotspot.X; - iconinfo.yHotspot = hotspot.Y; - iconinfo.hbmMask = andBitmap; - iconinfo.hbmColor = xorBitmap; - - HCURSOR cursor = CreateIconIndirect(&iconinfo); - - DeleteObject(andBitmap); - DeleteObject(xorBitmap); - - return cursor; -} - -CIrrDeviceWin32::CCursorControl::CCursorControl(CIrrDeviceWin32 *device, const core::dimension2d &wsize, HWND hwnd, bool fullscreen) : - Device(device), WindowSize(wsize), InvWindowSize(0.0f, 0.0f), - HWnd(hwnd), BorderX(0), BorderY(0), - UseReferenceRect(false), IsVisible(true), ActiveIcon(gui::ECI_NORMAL), ActiveIconStartTime(0) -{ - if (WindowSize.Width != 0) - InvWindowSize.Width = 1.0f / WindowSize.Width; - - if (WindowSize.Height != 0) - InvWindowSize.Height = 1.0f / WindowSize.Height; - - updateBorderSize(fullscreen, false); - initCursors(); -} - -CIrrDeviceWin32::CCursorControl::~CCursorControl() -{ - for (u32 i = 0; i < Cursors.size(); ++i) { - for (u32 f = 0; f < Cursors[i].Frames.size(); ++f) { - DestroyCursor(Cursors[i].Frames[f].IconHW); - } - } -} - -void CIrrDeviceWin32::CCursorControl::initCursors() -{ - Cursors.push_back(CursorW32(LoadCursor(NULL, IDC_ARROW))); - Cursors.push_back(CursorW32(LoadCursor(NULL, IDC_CROSS))); - Cursors.push_back(CursorW32(LoadCursor(NULL, IDC_HAND))); - Cursors.push_back(CursorW32(LoadCursor(NULL, IDC_HELP))); - Cursors.push_back(CursorW32(LoadCursor(NULL, IDC_IBEAM))); - Cursors.push_back(CursorW32(LoadCursor(NULL, IDC_NO))); - Cursors.push_back(CursorW32(LoadCursor(NULL, IDC_WAIT))); - Cursors.push_back(CursorW32(LoadCursor(NULL, IDC_SIZEALL))); - Cursors.push_back(CursorW32(LoadCursor(NULL, IDC_SIZENESW))); - Cursors.push_back(CursorW32(LoadCursor(NULL, IDC_SIZENWSE))); - Cursors.push_back(CursorW32(LoadCursor(NULL, IDC_SIZENS))); - Cursors.push_back(CursorW32(LoadCursor(NULL, IDC_SIZEWE))); - Cursors.push_back(CursorW32(LoadCursor(NULL, IDC_UPARROW))); -} - -void CIrrDeviceWin32::CCursorControl::update() -{ - if (!Cursors[ActiveIcon].Frames.empty() && Cursors[ActiveIcon].FrameTime) { - // update animated cursors. This could also be done by X11 in case someone wants to figure that out (this way was just easier to implement) - u32 now = Device->getTimer()->getRealTime(); - u32 frame = ((now - ActiveIconStartTime) / Cursors[ActiveIcon].FrameTime) % Cursors[ActiveIcon].Frames.size(); - SetCursor(Cursors[ActiveIcon].Frames[frame].IconHW); - } -} - -//! Sets the active cursor icon -void CIrrDeviceWin32::CCursorControl::setActiveIcon(gui::ECURSOR_ICON iconId) -{ - if (iconId >= (s32)Cursors.size()) - return; - - ActiveIcon = iconId; - ActiveIconStartTime = Device->getTimer()->getRealTime(); - if (Cursors[ActiveIcon].Frames.size()) - SetCursor(Cursors[ActiveIcon].Frames[0].IconHW); -} - -//! Add a custom sprite as cursor icon. -gui::ECURSOR_ICON CIrrDeviceWin32::CCursorControl::addIcon(const gui::SCursorSprite &icon) -{ - if (icon.SpriteId >= 0) { - CursorW32 cW32; - cW32.FrameTime = icon.SpriteBank->getSprites()[icon.SpriteId].frameTime; - - for (u32 i = 0; i < icon.SpriteBank->getSprites()[icon.SpriteId].Frames.size(); ++i) { - u32 texId = icon.SpriteBank->getSprites()[icon.SpriteId].Frames[i].textureNumber; - u32 rectId = icon.SpriteBank->getSprites()[icon.SpriteId].Frames[i].rectNumber; - core::rect rectIcon = icon.SpriteBank->getPositions()[rectId]; - - HCURSOR hc = Device->TextureToCursor(HWnd, icon.SpriteBank->getTexture(texId), rectIcon, icon.HotSpot); - cW32.Frames.push_back(CursorFrameW32(hc)); - } - - Cursors.push_back(cW32); - return (gui::ECURSOR_ICON)(Cursors.size() - 1); - } - return gui::ECI_NORMAL; -} - -//! replace the given cursor icon. -void CIrrDeviceWin32::CCursorControl::changeIcon(gui::ECURSOR_ICON iconId, const gui::SCursorSprite &icon) -{ - if (iconId >= (s32)Cursors.size()) - return; - - for (u32 i = 0; i < Cursors[iconId].Frames.size(); ++i) - DestroyCursor(Cursors[iconId].Frames[i].IconHW); - - if (icon.SpriteId >= 0) { - CursorW32 cW32; - cW32.FrameTime = icon.SpriteBank->getSprites()[icon.SpriteId].frameTime; - for (u32 i = 0; i < icon.SpriteBank->getSprites()[icon.SpriteId].Frames.size(); ++i) { - u32 texId = icon.SpriteBank->getSprites()[icon.SpriteId].Frames[i].textureNumber; - u32 rectId = icon.SpriteBank->getSprites()[icon.SpriteId].Frames[i].rectNumber; - core::rect rectIcon = icon.SpriteBank->getPositions()[rectId]; - - HCURSOR hc = Device->TextureToCursor(HWnd, icon.SpriteBank->getTexture(texId), rectIcon, icon.HotSpot); - cW32.Frames.push_back(CursorFrameW32(hc)); - } - - Cursors[iconId] = cW32; - } -} - -//! Return a system-specific size which is supported for cursors. Larger icons will fail, smaller icons might work. -core::dimension2di CIrrDeviceWin32::CCursorControl::getSupportedIconSize() const -{ - core::dimension2di result; - - result.Width = GetSystemMetrics(SM_CXCURSOR); - result.Height = GetSystemMetrics(SM_CYCURSOR); - - return result; -} - -#endif // _IRR_COMPILE_WITH_WINDOWS_DEVICE_ diff --git a/irr/src/CIrrDeviceWin32.h b/irr/src/CIrrDeviceWin32.h deleted file mode 100644 index 3d4b348b3b..0000000000 --- a/irr/src/CIrrDeviceWin32.h +++ /dev/null @@ -1,402 +0,0 @@ -// Copyright (C) 2002-2012 Nikolaus Gebhardt -// This file is part of the "Irrlicht Engine". -// For conditions of distribution and use, see copyright notice in irrlicht.h - -#pragma once - -#ifdef _IRR_COMPILE_WITH_WINDOWS_DEVICE_ - -#include "CIrrDeviceStub.h" -#include "IrrlichtDevice.h" -#include "ITexture.h" - -#define WIN32_LEAN_AND_MEAN -#include -#include // For JOYCAPS -#include -#if !defined(GET_X_LPARAM) -#define GET_X_LPARAM(lp) ((int)(short)LOWORD(lp)) -#define GET_Y_LPARAM(lp) ((int)(short)HIWORD(lp)) -#endif - -struct SJoystickWin32Control; - -class CIrrDeviceWin32 : public CIrrDeviceStub -{ - friend struct SJoystickWin32Control; - -public: - //! constructor - CIrrDeviceWin32(const SIrrlichtCreationParameters ¶ms); - - //! destructor - virtual ~CIrrDeviceWin32(); - - //! runs the device. Returns false if device wants to be deleted - bool run() override; - - //! Cause the device to temporarily pause execution and let other processes to run - // This should bring down processor usage without major performance loss for Irrlicht - void yield() override; - - //! Pause execution and let other processes to run for a specified amount of time. - void sleep(u32 timeMs, bool pauseTimer) override; - - //! sets the caption of the window - void setWindowCaption(const wchar_t *text) override; - - //! Sets the window icon. - bool setWindowIcon(const video::IImage *img) override; - - //! returns if window is active. if not, nothing need to be drawn - bool isWindowActive() const override; - - //! returns if window has focus - bool isWindowFocused() const override; - - //! returns if window is minimized - bool isWindowMinimized() const override; - - //! returns last state from maximizeWindow() and restoreWindow() - bool isWindowMaximized() const override; - - //! notifies the device that it should close itself - void closeDevice() override; - - //! Notifies the device, that it has been resized - /** Must be publis as it is called from free function (event handler) */ - void OnResized(); - - //! Sets if the window should be resizable in windowed mode. - void setResizable(bool resize = false) override; - - //! Resize the render window. - void setWindowSize(const core::dimension2d &size) override; - - //! Minimizes the window. - void minimizeWindow() override; - - //! Maximizes the window. - void maximizeWindow() override; - - //! Restores the window size. - void restoreWindow() override; - - //! Get the position of the window on screen - core::position2di getWindowPosition() override; - - //! Activate any joysticks, and generate events for them. - bool activateJoysticks(core::array &joystickInfo) override; - - //! Remove all messages pending in the system message loop - void clearSystemMessages() override; - - //! Get the device type - E_DEVICE_TYPE getType() const override - { - return EIDT_WIN32; - } - - //! Get the display density in dots per inch. - float getDisplayDensity() const override; - - //! Compares to the last call of this function to return double and triple clicks. - //! \return Returns only 1,2 or 3. A 4th click will start with 1 again. - u32 checkSuccessiveClicks(s32 mouseX, s32 mouseY, EMOUSE_INPUT_EVENT inputEvent) override - { - // we just have to make it public - return CIrrDeviceStub::checkSuccessiveClicks(mouseX, mouseY, inputEvent); - } - - //! Switch to fullscreen - bool switchToFullScreen(); - - // convert an Irrlicht texture to a windows cursor - HCURSOR TextureToCursor(HWND hwnd, video::ITexture *tex, const core::rect &sourceRect, const core::position2d &hotspot); - - //! Implementation of the win32 cursor control - class CCursorControl : public gui::ICursorControl - { - public: - CCursorControl(CIrrDeviceWin32 *device, const core::dimension2d &wsize, HWND hwnd, bool fullscreen); - ~CCursorControl(); - - //! Changes the visible state of the mouse cursor. - void setVisible(bool visible) override - { - CURSORINFO info; - info.cbSize = sizeof(CURSORINFO); - BOOL gotCursorInfo = GetCursorInfo(&info); - while (gotCursorInfo) { -#ifdef CURSOR_SUPPRESSED - // Since Windows 8 the cursor can be suppressed by a touch interface - if (visible && info.flags == CURSOR_SUPPRESSED) { - break; - } -#endif - if ((visible && info.flags == CURSOR_SHOWING) || // visible - (!visible && info.flags == 0)) // hidden - { - break; - } - // this only increases an internal - // display counter in windows, so it - // might have to be called some more - const int showResult = ShowCursor(visible); - // if result has correct sign we can - // stop here as well - if ((!visible && showResult < 0) || - (visible && showResult >= 0)) - break; - // yes, it really must be set each time - info.cbSize = sizeof(CURSORINFO); - gotCursorInfo = GetCursorInfo(&info); - -#ifdef CURSOR_SUPPRESSED - // Not sure if a cursor which we tried to hide still can be suppressed. - // I have no touch-display for testing this and MSDN doesn't describe it. - // But adding this check shouldn't hurt and might prevent an endless loop. - if (!visible && info.flags == CURSOR_SUPPRESSED) { - break; - } -#endif - } - IsVisible = visible; - } - - //! Returns if the cursor is currently visible. - bool isVisible() const override - { - return IsVisible; - } - - //! Sets the new position of the cursor. - void setPosition(const core::position2d &pos) override - { - setPosition(pos.X, pos.Y); - } - - //! Sets the new position of the cursor. - void setPosition(f32 x, f32 y) override - { - if (!UseReferenceRect) - setPosition(core::round32(x * WindowSize.Width), core::round32(y * WindowSize.Height)); - else - setPosition(core::round32(x * ReferenceRect.getWidth()), core::round32(y * ReferenceRect.getHeight())); - } - - //! Sets the new position of the cursor. - void setPosition(const core::position2d &pos) override - { - setPosition(pos.X, pos.Y); - } - - //! Sets the new position of the cursor. - void setPosition(s32 x, s32 y) override - { - if (UseReferenceRect) { - SetCursorPos(ReferenceRect.UpperLeftCorner.X + x, - ReferenceRect.UpperLeftCorner.Y + y); - } else { - RECT rect; - if (GetWindowRect(HWnd, &rect)) - SetCursorPos(x + rect.left + BorderX, y + rect.top + BorderY); - } - - CursorPos.X = x; - CursorPos.Y = y; - } - - //! Returns the current position of the mouse cursor. - const core::position2d &getPosition(bool updateCursor) override - { - if (updateCursor) - updateInternalCursorPosition(); - return CursorPos; - } - - //! Returns the current position of the mouse cursor. - core::position2d getRelativePosition(bool updateCursor) override - { - if (updateCursor) - updateInternalCursorPosition(); - - if (!UseReferenceRect) { - return core::position2d(CursorPos.X * InvWindowSize.Width, - CursorPos.Y * InvWindowSize.Height); - } - - return core::position2d(CursorPos.X / (f32)ReferenceRect.getWidth(), - CursorPos.Y / (f32)ReferenceRect.getHeight()); - } - - //! Sets an absolute reference rect for calculating the cursor position. - void setReferenceRect(core::rect *rect = 0) override - { - if (rect) { - ReferenceRect = *rect; - UseReferenceRect = true; - - // prevent division through zero and uneven sizes - - if (!ReferenceRect.getHeight() || ReferenceRect.getHeight() % 2) - ReferenceRect.LowerRightCorner.Y += 1; - - if (!ReferenceRect.getWidth() || ReferenceRect.getWidth() % 2) - ReferenceRect.LowerRightCorner.X += 1; - } else - UseReferenceRect = false; - } - - /** Used to notify the cursor that the window was resized. */ - void OnResize(const core::dimension2d &size) - { - WindowSize = size; - if (size.Width != 0) - InvWindowSize.Width = 1.0f / size.Width; - else - InvWindowSize.Width = 0.f; - - if (size.Height != 0) - InvWindowSize.Height = 1.0f / size.Height; - else - InvWindowSize.Height = 0.f; - } - - /** Used to notify the cursor that the window resizable settings changed. */ - void updateBorderSize(bool fullscreen, bool resizable) - { - if (!fullscreen) { - s32 paddingBorder = 0; -#ifdef SM_CXPADDEDBORDER - paddingBorder = GetSystemMetrics(SM_CXPADDEDBORDER); -#endif - - if (resizable) { - BorderX = GetSystemMetrics(SM_CXSIZEFRAME) + paddingBorder; - BorderY = GetSystemMetrics(SM_CYCAPTION) + GetSystemMetrics(SM_CYSIZEFRAME) + paddingBorder; - } else { - BorderX = GetSystemMetrics(SM_CXDLGFRAME) + paddingBorder; - BorderY = GetSystemMetrics(SM_CYCAPTION) + GetSystemMetrics(SM_CYDLGFRAME) + paddingBorder; - } - } else { - BorderX = BorderY = 0; - } - } - - //! Sets the active cursor icon - void setActiveIcon(gui::ECURSOR_ICON iconId) override; - - //! Gets the currently active icon - gui::ECURSOR_ICON getActiveIcon() const override - { - return ActiveIcon; - } - - //! Add a custom sprite as cursor icon. - gui::ECURSOR_ICON addIcon(const gui::SCursorSprite &icon) override; - - //! replace the given cursor icon. - void changeIcon(gui::ECURSOR_ICON iconId, const gui::SCursorSprite &icon) override; - - //! Return a system-specific size which is supported for cursors. Larger icons will fail, smaller icons might work. - core::dimension2di getSupportedIconSize() const override; - - void update(); - - private: - //! Updates the internal cursor position - void updateInternalCursorPosition() - { - POINT p; - if (!GetCursorPos(&p)) { - DWORD xy = GetMessagePos(); - p.x = GET_X_LPARAM(xy); - p.y = GET_Y_LPARAM(xy); - } - - if (UseReferenceRect) { - CursorPos.X = p.x - ReferenceRect.UpperLeftCorner.X; - CursorPos.Y = p.y - ReferenceRect.UpperLeftCorner.Y; - } else { - RECT rect; - if (GetWindowRect(HWnd, &rect)) { - CursorPos.X = p.x - rect.left - BorderX; - CursorPos.Y = p.y - rect.top - BorderY; - } else { - // window seems not to be existent, so set cursor to - // a negative value - CursorPos.X = -1; - CursorPos.Y = -1; - } - } - } - - CIrrDeviceWin32 *Device; - core::position2d CursorPos; - core::dimension2d WindowSize; - core::dimension2d InvWindowSize; - HWND HWnd; - - s32 BorderX, BorderY; - core::rect ReferenceRect; - bool UseReferenceRect; - bool IsVisible; - - struct CursorFrameW32 - { - CursorFrameW32() : - IconHW(0) {} - CursorFrameW32(HCURSOR icon) : - IconHW(icon) {} - - HCURSOR IconHW; // hardware cursor - }; - - struct CursorW32 - { - CursorW32() {} - explicit CursorW32(HCURSOR iconHw, u32 frameTime = 0) : - FrameTime(frameTime) - { - Frames.push_back(CursorFrameW32(iconHw)); - } - core::array Frames; - u32 FrameTime; - }; - - core::array Cursors; - gui::ECURSOR_ICON ActiveIcon; - u32 ActiveIconStartTime; - - void initCursors(); - }; - - //! returns the win32 cursor control - CCursorControl *getWin32CursorControl(); - -private: - //! create the driver - void createDriver(); - - //! Process system events - void handleSystemMessages(); - - void getWindowsVersion(core::stringc &version); - - void resizeIfNecessary(); - - DWORD getWindowStyle(bool fullscreen, bool resizable) const; - - HWND HWnd; - - bool Resized; - bool ExternalWindow; - CCursorControl *Win32CursorControl; - - SJoystickWin32Control *JoyControl; - - bool WindowMaximized; -}; - -#endif // _IRR_COMPILE_WITH_WINDOWS_DEVICE_ diff --git a/irr/src/CMakeLists.txt b/irr/src/CMakeLists.txt index b7360311aa..aabdf9c944 100644 --- a/irr/src/CMakeLists.txt +++ b/irr/src/CMakeLists.txt @@ -1,7 +1,3 @@ -set(DEFAULT_SDL2 ON) - -option(USE_SDL2 "Use the SDL2 backend" ${DEFAULT_SDL2}) - option(USE_SDL2_STATIC "Link with SDL2 static libraries" FALSE) # Compiler flags @@ -62,26 +58,18 @@ endif() if(WIN32) add_compile_definitions(_IRR_WINDOWS_ _IRR_WINDOWS_API_) - set(DEVICE "WINDOWS") elseif(APPLE) add_compile_definitions(_IRR_OSX_PLATFORM_) - set(DEVICE "OSX") elseif(ANDROID) add_compile_definitions(_IRR_ANDROID_PLATFORM_) - if(NOT USE_SDL2) - message(FATAL_ERROR "The Android build requires SDL2") - endif() elseif(EMSCRIPTEN) add_compile_definitions(_IRR_EMSCRIPTEN_PLATFORM_ _IRR_COMPILE_WITH_EGL_MANAGER_) set(LINUX_PLATFORM TRUE) - set(DEVICE "SDL") elseif(SOLARIS) add_compile_definitions(_IRR_SOLARIS_PLATFORM_ _IRR_POSIX_API_) - set(DEVICE "X11") else() add_compile_definitions(_IRR_POSIX_API_) set(LINUX_PLATFORM TRUE) - set(DEVICE "X11") endif() if(LINUX_PLATFORM) @@ -92,29 +80,7 @@ if(MSVC) add_compile_definitions(_CRT_SECURE_NO_WARNINGS) endif() -if(USE_SDL2) - set(DEVICE "SDL") -elseif(DEVICE STREQUAL "SDL") - message(FATAL_ERROR "SDL was used but not enabled?!") -endif() - -add_compile_definitions("_IRR_COMPILE_WITH_${DEVICE}_DEVICE_") - -# X11 - -if(DEVICE STREQUAL "X11") - option(USE_X11 "Use X11" TRUE) -else() - set(USE_X11 FALSE) -endif() - -if(LINUX_PLATFORM AND USE_X11) - option(USE_XINPUT2 "Use XInput2" TRUE) - option(USE_XCURSOR "Use XCursor" FALSE) -else() - set(USE_XINPUT2 FALSE) - set(USE_XCURSOR FALSE) -endif() +add_compile_definitions("_IRR_COMPILE_WITH_SDL_DEVICE_") # Joystick @@ -122,14 +88,10 @@ if(NOT (BSD OR SOLARIS OR EMSCRIPTEN)) add_compile_definitions(_IRR_COMPILE_WITH_JOYSTICK_EVENTS_) endif() -# OpenGL +# OpenGL (ES) -if(USE_SDL2) - if(NOT ANDROID) - set(DEFAULT_OPENGL3 TRUE) - endif() -else() - set(DEFAULT_OPENGL3 FALSE) +if(NOT ANDROID) + set(DEFAULT_OPENGL3 TRUE) endif() option(ENABLE_OPENGL3 "Enable OpenGL 3+" ${DEFAULT_OPENGL3}) @@ -157,35 +119,13 @@ else() endif() endif() -if(ENABLE_OPENGL OR (ENABLE_OPENGL3 AND NOT USE_SDL2)) - if(ENABLE_OPENGL) - add_compile_definitions(_IRR_COMPILE_WITH_OPENGL_) - set(OPENGL_DIRECT_LINK TRUE) # driver relies on this - endif() - if(DEVICE STREQUAL "WINDOWS") - add_compile_definitions(_IRR_COMPILE_WITH_WGL_MANAGER_) - elseif(DEVICE STREQUAL "X11") - add_compile_definitions(_IRR_COMPILE_WITH_GLX_MANAGER_) - elseif(DEVICE STREQUAL "OSX") - add_compile_definitions(_IRR_COMPILE_WITH_NSOGL_MANAGER_) - endif() -endif() - -if(ENABLE_OPENGL3) - if(DEVICE STREQUAL "WINDOWS") - # supported - elseif(DEVICE STREQUAL "X11") - # supported - elseif (NOT USE_SDL2) - message(FATAL_ERROR "OpenGL 3 driver requires SDL2") - endif() +if(ENABLE_OPENGL) + add_compile_definitions(_IRR_COMPILE_WITH_OPENGL_) + set(OPENGL_DIRECT_LINK TRUE) # driver relies on this endif() if(ENABLE_GLES2) add_compile_definitions(_IRR_COMPILE_WITH_OGLES2_) - if(DEVICE MATCHES "^(WINDOWS|X11)$" OR EMSCRIPTEN) - add_compile_definitions(_IRR_COMPILE_WITH_EGL_MANAGER_) - endif() endif() if(ENABLE_WEBGL1) @@ -202,7 +142,6 @@ endif() # Configuration report -message(STATUS "Device: ${DEVICE}") message(STATUS "OpenGL: ${ENABLE_OPENGL}") message(STATUS "OpenGL 3: ${ENABLE_OPENGL3}") if (ENABLE_GLES2) @@ -227,7 +166,7 @@ if(ENABLE_OPENGL) find_package(OpenGL REQUIRED) endif() set(USE_SDL2_SHARED FALSE) -if(USE_SDL2) +if(TRUE) if(NOT USE_SDL2_STATIC) set(USE_SDL2_SHARED TRUE) endif() @@ -260,7 +199,7 @@ endif() # More special config -if(ENABLE_OPENGL AND DEVICE STREQUAL "SDL") +if(ENABLE_OPENGL) # The legacy GL driver requires some symbols from GL 4.5 to compile, # which SDL only provides since 2.26.0 (Nov 2022). # We have a fallback in case this isn't satisfied so test for it. @@ -278,19 +217,8 @@ endif() # Platform-specific libs -if(ANDROID) - enable_language(C) -elseif(APPLE) - find_library(COCOA_LIB Cocoa REQUIRED) - find_library(IOKIT_LIB IOKit REQUIRED) - +if(APPLE) add_compile_definitions(GL_SILENCE_DEPRECATION) -elseif(NOT USE_SDL2) - # Unix probably - find_package(X11 REQUIRED) - if(USE_XINPUT2 AND NOT X11_Xi_FOUND) - message(FATAL_ERROR "XInput not found") - endif() endif() set(link_includes @@ -300,13 +228,11 @@ set(link_includes "${ZLIB_INCLUDE_DIR}" "${JPEG_INCLUDE_DIR}" "${PNG_INCLUDE_DIR}" - "$<$:${SDL2_INCLUDE_DIRS}>" + "${SDL2_INCLUDE_DIRS}" ${OPENGL_INCLUDE_DIR} ${OPENGLES2_INCLUDE_DIR} ${EGL_INCLUDE_DIR} - - "$<$:${X11_INCLUDE_DIR}>" ) # Source files @@ -338,14 +264,10 @@ target_link_libraries(IRRMESHOBJ PUBLIC tiniergltf::tiniergltf) set(IRRDRVROBJ CNullDriver.h - CGLXManager.h - CWGLManager.h CEGLManager.h CSDLManager.h CNullDriver.cpp - CGLXManager.cpp - CWGLManager.cpp CEGLManager.cpp CSDLManager.cpp mt_opengl_loader.cpp @@ -446,17 +368,13 @@ add_library(IRRIOOBJ OBJECT add_library(IRROTHEROBJ OBJECT CIrrDeviceSDL.h - CIrrDeviceLinux.h CIrrDeviceStub.h - CIrrDeviceWin32.h CLogger.h COSOperator.h os.h CIrrDeviceSDL.cpp - CIrrDeviceLinux.cpp CIrrDeviceStub.cpp - CIrrDeviceWin32.cpp CLogger.cpp COSOperator.cpp Irrlicht.cpp @@ -470,22 +388,6 @@ endif() if(APPLE) # Build all IRROTHEROBJ sources as objc++, including the .cpp's set_target_properties(IRROTHEROBJ PROPERTIES COMPILE_OPTIONS "-xobjective-c++") - target_sources(IRROTHEROBJ PRIVATE - CIrrDeviceOSX.mm - CNSOGLManager.mm - ) -endif() - -if(USE_X11) - target_compile_definitions(IRROTHEROBJ PRIVATE _IRR_COMPILE_WITH_X11_) -endif() - -if(USE_XINPUT2) - target_compile_definitions(IRROTHEROBJ PRIVATE _IRR_LINUX_X11_XINPUT2_) -endif() - -if(USE_XCURSOR) - target_compile_definitions(IRROTHEROBJ PRIVATE _IRR_LINUX_XCURSOR_) endif() add_library(IRRGUIOBJ OBJECT @@ -591,12 +493,6 @@ target_link_libraries(IrrlichtMt PRIVATE # incl. transitive SDL2 dependencies for static linking "$<$:-landroid -llog -lGLESv2 -lGLESv1_CM -lOpenSLES>" - ${COCOA_LIB} - ${IOKIT_LIB} - "$<$:gdi32>" - "$<$:winmm>" - "$<$:${X11_X11_LIB}>" - "$<$:${X11_Xi_LIB}>" ) if(WIN32) diff --git a/irr/src/CNSOGLManager.h b/irr/src/CNSOGLManager.h deleted file mode 100644 index d0e848b876..0000000000 --- a/irr/src/CNSOGLManager.h +++ /dev/null @@ -1,67 +0,0 @@ -// Copyright (C) 2014 Patryk Nadrowski -// This file is part of the "Irrlicht Engine". -// For conditions of distribution and use, see copyright notice in Irrlicht.h - -#pragma once - -#ifdef _IRR_COMPILE_WITH_NSOGL_MANAGER_ - -#include "SIrrCreationParameters.h" -#include "SExposedVideoData.h" -#include "IContextManager.h" -#include "SColor.h" - -#import - -namespace video -{ -// NSOpenGL manager. -class CNSOGLManager : public IContextManager -{ -public: - //! Constructor. - CNSOGLManager(); - - //! Destructor - ~CNSOGLManager(); - - // Initialize - bool initialize(const SIrrlichtCreationParameters ¶ms, const SExposedVideoData &data) override; - - // Terminate - void terminate() override; - - // Create surface. - bool generateSurface() override; - - // Destroy surface. - void destroySurface() override; - - // Create context. - bool generateContext() override; - - // Destroy EGL context. - void destroyContext() override; - - //! Get current context - const SExposedVideoData &getContext() const; - - //! Change render context, disable old and activate new defined by videoData - bool activateContext(const SExposedVideoData &videoData, bool restorePrimaryOnZero) override; - - // Get procedure address. - void *getProcAddress(const std::string &procName) override; - - // Swap buffers. - bool swapBuffers() override; - -private: - SIrrlichtCreationParameters Params; - SExposedVideoData PrimaryContext; - SExposedVideoData CurrentContext; - - NSOpenGLPixelFormat *PixelFormat; -}; -} - -#endif diff --git a/irr/src/CNSOGLManager.mm b/irr/src/CNSOGLManager.mm deleted file mode 100644 index 5a369d6f9e..0000000000 --- a/irr/src/CNSOGLManager.mm +++ /dev/null @@ -1,227 +0,0 @@ -// Copyright (C) 2014 Patryk Nadrowski -// This file is part of the "Irrlicht Engine". -// For conditions of distribution and use, see copyright notice in Irrlicht.h - -#include "CNSOGLManager.h" - -#ifdef _IRR_COMPILE_WITH_NSOGL_MANAGER_ - -#include -#include "os.h" - -namespace video -{ - -CNSOGLManager::CNSOGLManager() : - PrimaryContext(SExposedVideoData(0)), PixelFormat(nil) -{} - -CNSOGLManager::~CNSOGLManager() -{ -} - -bool CNSOGLManager::initialize(const SIrrlichtCreationParameters ¶ms, const SExposedVideoData &videodata) -{ - Params = params; - - return true; -} - -void CNSOGLManager::terminate() -{ -} - -bool CNSOGLManager::generateSurface() -{ - if (Params.DriverType == video::EDT_OPENGL) { - int alphaSize = Params.WithAlphaChannel ? 4 : 0; - int depthSize = Params.ZBufferBits; - - if (Params.WithAlphaChannel && Params.Bits == 32) - alphaSize = 8; - - NSOpenGLPixelFormatAttribute Attribs[] = { - NSOpenGLPFANoRecovery, - NSOpenGLPFAAccelerated, - NSOpenGLPFADoubleBuffer, - NSOpenGLPFADepthSize, static_cast(depthSize), - NSOpenGLPFAColorSize, Params.Bits, - NSOpenGLPFAAlphaSize, static_cast(alphaSize), - NSOpenGLPFASampleBuffers, 1, - NSOpenGLPFASamples, Params.AntiAlias, - NSOpenGLPFAStencilSize, static_cast(Params.Stencilbuffer ? 1 : 0), - // NSOpenGLPFAFullScreen, - 0, - }; - - u32 Steps = 6; - - // Choose the best pixel format. - do { - switch (Steps) { - case 6: // decrease step. - --Steps; - break; - case 5: // samples - if (Attribs[12] > 2) - --Attribs[12]; - else { - Attribs[10] = 0; - Attribs[12] = 0; - --Steps; - } - break; - case 4: // alpha - if (Attribs[8]) { - Attribs[8] = 0; - - if (Params.AntiAlias) { - Attribs[10] = 1; - Attribs[12] = Params.AntiAlias; - Steps = 5; - } - } else - --Steps; - break; - case 3: // stencil - if (Attribs[14]) { - Attribs[14] = 0; - - if (Params.AntiAlias) { - Attribs[10] = 1; - Attribs[12] = Params.AntiAlias; - Steps = 5; - } - } else - --Steps; - break; - case 2: // depth size - if (Attribs[4] > 16) { - Attribs[4] = Attribs[4] - 8; - } else - --Steps; - break; - case 1: // buffer size - if (Attribs[6] > 16) { - Attribs[6] = Attribs[6] - 8; - } else - --Steps; - break; - default: - os::Printer::log("Could not get pixel format."); - return false; - } - - PixelFormat = [[NSOpenGLPixelFormat alloc] initWithAttributes:Attribs]; - } while (PixelFormat == nil); - - if (Params.AntiAlias && !Attribs[10]) - os::Printer::log("No multisampling."); - - if (Params.WithAlphaChannel && !Attribs[8]) - os::Printer::log("No alpha."); - - if (Params.Stencilbuffer && !Attribs[14]) - os::Printer::log("No stencil buffer."); - - if (Params.ZBufferBits > Attribs[4]) - os::Printer::log("No full depth buffer."); - - if (Params.Bits > Attribs[6]) - os::Printer::log("No full color buffer."); - } - - return true; -} - -void CNSOGLManager::destroySurface() -{ - [PixelFormat release]; - PixelFormat = nil; -} - -bool CNSOGLManager::generateContext() -{ - NSOpenGLContext *Context = [[NSOpenGLContext alloc] initWithFormat:PixelFormat shareContext:nil]; - - GLint Vsync = Params.Vsync ? 1 : 0; - [Context setValues:&Vsync forParameter:NSOpenGLCPSwapInterval]; - - if (Context == nil) { - os::Printer::log("Could not create OpenGL context.", ELL_ERROR); - return false; - } - - // set exposed data - CurrentContext.OpenGLOSX.Context = Context; - - if (!PrimaryContext.OpenGLOSX.Context) - PrimaryContext.OpenGLOSX.Context = CurrentContext.OpenGLOSX.Context; - - return true; -} - -const SExposedVideoData &CNSOGLManager::getContext() const -{ - return CurrentContext; -} - -bool CNSOGLManager::activateContext(const SExposedVideoData &videoData, bool restorePrimaryOnZero) -{ - // TODO: handle restorePrimaryOnZero - if (videoData.OpenGLOSX.Context) { - if ((NSOpenGLContext *)videoData.OpenGLOSX.Context != [NSOpenGLContext currentContext]) { - [(NSOpenGLContext *)videoData.OpenGLOSX.Context makeCurrentContext]; - - CurrentContext = videoData; - } - } - // set back to main context - else { - if ((NSOpenGLContext *)PrimaryContext.OpenGLOSX.Context != [NSOpenGLContext currentContext]) { - [(NSOpenGLContext *)PrimaryContext.OpenGLOSX.Context makeCurrentContext]; - - CurrentContext = PrimaryContext; - } - } - - return true; -} - -void CNSOGLManager::destroyContext() -{ - if (CurrentContext.OpenGLOSX.Context) { - if (PrimaryContext.OpenGLOSX.Context == CurrentContext.OpenGLOSX.Context) - PrimaryContext.OpenGLOSX.Context = nil; - - [(NSOpenGLContext *)CurrentContext.OpenGLOSX.Context makeCurrentContext]; - [(NSOpenGLContext *)CurrentContext.OpenGLOSX.Context clearDrawable]; - [(NSOpenGLContext *)CurrentContext.OpenGLOSX.Context release]; - [NSOpenGLContext clearCurrentContext]; - - CurrentContext.OpenGLOSX.Context = nil; - } -} - -// It appears that there is no separate GL proc address getter on OSX. -// https://developer.apple.com/library/archive/documentation/GraphicsImaging/Conceptual/OpenGL-MacProgGuide/opengl_entrypts/opengl_entrypts.html -void *CNSOGLManager::getProcAddress(const std::string &procName) -{ - NSSymbol symbol = NULL; - // Allocate a buffer for the name, an underscore prefix, and a cstring terminator. - std::string mangledName = "_" + procName; - if (NSIsSymbolNameDefined(mangledName.c_str())) - symbol = NSLookupAndBindSymbol(mangledName.c_str()); - return symbol ? NSAddressOfSymbol(symbol) : NULL; -} - -bool CNSOGLManager::swapBuffers() -{ - [(NSOpenGLContext *)CurrentContext.OpenGLOSX.Context flushBuffer]; - - return true; -} - -} - -#endif diff --git a/irr/src/COSOperator.cpp b/irr/src/COSOperator.cpp index d2c10b6646..e88dc4cfc1 100644 --- a/irr/src/COSOperator.cpp +++ b/irr/src/COSOperator.cpp @@ -20,23 +20,10 @@ #if defined(_IRR_COMPILE_WITH_SDL_DEVICE_) #include #include -#elif defined(_IRR_COMPILE_WITH_X11_DEVICE_) -#include "CIrrDeviceLinux.h" -#endif -#if defined(_IRR_COMPILE_WITH_OSX_DEVICE_) -#import #endif #include "fast_atof.h" -#if defined(_IRR_COMPILE_WITH_X11_DEVICE_) -// constructor linux -COSOperator::COSOperator(const core::stringc &osVersion, CIrrDeviceLinux *device) : - OperatingSystem(osVersion), IrrDeviceLinux(device) -{ -} -#endif - // constructor COSOperator::COSOperator(const core::stringc &osVersion) : OperatingSystem(osVersion) @@ -64,43 +51,6 @@ void COSOperator::copyToClipboard(const c8 *text) const #if defined(_IRR_COMPILE_WITH_SDL_DEVICE_) SDL_SetClipboardText(text); - -#elif defined(_IRR_WINDOWS_API_) - if (!OpenClipboard(NULL) || text == 0) - return; - - EmptyClipboard(); - - core::stringw tempbuffer; - core::utf8ToWString(tempbuffer, text); - const u32 size = (tempbuffer.size() + 1) * sizeof(wchar_t); - - HGLOBAL clipbuffer; - void *buffer; - - clipbuffer = GlobalAlloc(GMEM_MOVEABLE, size); - buffer = GlobalLock(clipbuffer); - - memcpy(buffer, tempbuffer.c_str(), size); - - GlobalUnlock(clipbuffer); - SetClipboardData(CF_UNICODETEXT, clipbuffer); - CloseClipboard(); - -#elif defined(_IRR_COMPILE_WITH_OSX_DEVICE_) - NSString *str = nil; - NSPasteboard *board = nil; - - if ((text != NULL) && (strlen(text) > 0)) { - str = [NSString stringWithCString:text encoding:NSUTF8StringEncoding]; - board = [NSPasteboard generalPasteboard]; - [board declareTypes:[NSArray arrayWithObject:NSPasteboardTypeString] owner:NSApp]; - [board setString:str forType:NSPasteboardTypeString]; - } - -#elif defined(_IRR_COMPILE_WITH_X11_DEVICE_) - if (IrrDeviceLinux) - IrrDeviceLinux->copyToClipboard(text); #endif } @@ -114,10 +64,6 @@ void COSOperator::copyToPrimarySelection(const c8 *text) const #if SDL_VERSION_ATLEAST(2, 25, 0) SDL_SetPrimarySelectionText(text); #endif - -#elif defined(_IRR_COMPILE_WITH_X11_DEVICE_) - if (IrrDeviceLinux) - IrrDeviceLinux->copyToPrimarySelection(text); #endif } @@ -128,42 +74,6 @@ const c8 *COSOperator::getTextFromClipboard() const SDL_free(ClipboardSelectionText); ClipboardSelectionText = SDL_GetClipboardText(); return ClipboardSelectionText; - -#elif defined(_IRR_WINDOWS_API_) - if (!OpenClipboard(NULL)) - return 0; - - HANDLE hData = GetClipboardData(CF_UNICODETEXT); - if (hData == NULL) // Probably not in Unicode text format - return 0; - - wchar_t *buffer = (wchar_t *)GlobalLock(hData); - - core::wStringToUTF8(ClipboardBuf, buffer); - - GlobalUnlock(hData); - CloseClipboard(); - - return ClipboardBuf.c_str(); - -#elif defined(_IRR_COMPILE_WITH_OSX_DEVICE_) - NSString *str = nil; - NSPasteboard *board = nil; - char *result = 0; - - board = [NSPasteboard generalPasteboard]; - str = [board stringForType:NSPasteboardTypeString]; - - if (str != nil) - result = (char *)[str cStringUsingEncoding:NSUTF8StringEncoding]; - - return (result); - -#elif defined(_IRR_COMPILE_WITH_X11_DEVICE_) - if (IrrDeviceLinux) - return IrrDeviceLinux->getTextFromClipboard(); - return 0; - #else return 0; @@ -181,11 +91,6 @@ const c8 *COSOperator::getTextFromPrimarySelection() const #endif return 0; -#elif defined(_IRR_COMPILE_WITH_X11_DEVICE_) - if (IrrDeviceLinux) - return IrrDeviceLinux->getTextFromPrimarySelection(); - return 0; - #else return 0; @@ -238,7 +143,6 @@ bool COSOperator::getSystemMemory(u32 *Total, u32 *Avail) const *Avail = (u32)(physical_memory >> 10); // we don't know better return true; #else - // TODO: implement for others return false; #endif } diff --git a/irr/src/COSOperator.h b/irr/src/COSOperator.h index bc067bfcf2..745dbcb7b0 100644 --- a/irr/src/COSOperator.h +++ b/irr/src/COSOperator.h @@ -6,16 +6,11 @@ #include "IOSOperator.h" -class CIrrDeviceLinux; - //! The OSOperator provides OS-specific methods and information. class COSOperator : public IOSOperator { public: // constructor -#if defined(_IRR_COMPILE_WITH_X11_DEVICE_) - COSOperator(const core::stringc &osversion, CIrrDeviceLinux *device); -#endif COSOperator(const core::stringc &osversion); ~COSOperator(); @@ -53,10 +48,6 @@ public: private: core::stringc OperatingSystem; -#if defined(_IRR_COMPILE_WITH_X11_DEVICE_) - CIrrDeviceLinux *IrrDeviceLinux; -#endif - #ifdef _IRR_WINDOWS_API_ mutable core::stringc ClipboardBuf; #endif diff --git a/irr/src/COpenGLDriver.cpp b/irr/src/COpenGLDriver.cpp index ac0386b66f..873586835a 100644 --- a/irr/src/COpenGLDriver.cpp +++ b/irr/src/COpenGLDriver.cpp @@ -44,10 +44,6 @@ bool COpenGLDriver::initDriver() genericDriverInit(); -#if defined(_IRR_COMPILE_WITH_WINDOWS_DEVICE_) || defined(_IRR_COMPILE_WITH_X11_DEVICE_) - extGlSwapInterval(Params.Vsync ? 1 : 0); -#endif - return true; } diff --git a/irr/src/COpenGLExtensionHandler.cpp b/irr/src/COpenGLExtensionHandler.cpp index d2b2221fc2..f3ccac7e2d 100644 --- a/irr/src/COpenGLExtensionHandler.cpp +++ b/irr/src/COpenGLExtensionHandler.cpp @@ -89,22 +89,6 @@ COpenGLExtensionHandler::COpenGLExtensionHandler() : // DSA with EXT or functions to simulate it pGlTextureStorage2DEXT(0), pGlTexStorage2D(0), pGlTextureStorage3DEXT(0), pGlTexStorage3D(0), pGlTextureSubImage2DEXT(0), pGlGetTextureImageEXT(0), pGlNamedFramebufferTextureEXT(0), pGlFramebufferTexture(0), pGlGenerateTextureMipmapEXT(0) -#if defined(GLX_SGI_swap_control) - , - pGlxSwapIntervalSGI(0) -#endif -#if defined(GLX_EXT_swap_control) - , - pGlxSwapIntervalEXT(0) -#endif -#if defined(WGL_EXT_swap_control) - , - pWglSwapIntervalEXT(0) -#endif -#if defined(GLX_MESA_swap_control) - , - pGlxSwapIntervalMESA(0) -#endif { for (u32 i = 0; i < IRR_OpenGL_Feature_Count; ++i) FeatureAvailable[i] = false; @@ -360,20 +344,6 @@ void COpenGLExtensionHandler::initExtensions(video::IContextManager *cmgr, bool pGlActiveTexture = (PFNGLACTIVETEXTUREPROC)IRR_OGL_LOAD_EXTENSION("glActiveTexture"); pGlGenerateTextureMipmapEXT = (PFNGLGENERATETEXTUREMIPMAPEXTPROC)IRR_OGL_LOAD_EXTENSION("glGenerateTextureMipmapEXT"); -// get vsync extension -#if defined(WGL_EXT_swap_control) && !defined(_IRR_COMPILE_WITH_SDL_DEVICE_) - pWglSwapIntervalEXT = (PFNWGLSWAPINTERVALEXTPROC)IRR_OGL_LOAD_EXTENSION("wglSwapIntervalEXT"); -#endif -#if defined(GLX_SGI_swap_control) && !defined(_IRR_COMPILE_WITH_SDL_DEVICE_) - pGlxSwapIntervalSGI = (PFNGLXSWAPINTERVALSGIPROC)IRR_OGL_LOAD_EXTENSION("glXSwapIntervalSGI"); -#endif -#if defined(GLX_EXT_swap_control) && !defined(_IRR_COMPILE_WITH_SDL_DEVICE_) - pGlxSwapIntervalEXT = (PFNGLXSWAPINTERVALEXTPROC)IRR_OGL_LOAD_EXTENSION("glXSwapIntervalEXT"); -#endif -#if defined(GLX_MESA_swap_control) && !defined(_IRR_COMPILE_WITH_SDL_DEVICE_) - pGlxSwapIntervalMESA = (PFNGLXSWAPINTERVALMESAPROC)IRR_OGL_LOAD_EXTENSION("glXSwapIntervalMESA"); -#endif - GLint num = 0; // set some properties #if defined(GL_ARB_multitexture) || defined(GL_VERSION_1_3) diff --git a/irr/src/COpenGLExtensionHandler.h b/irr/src/COpenGLExtensionHandler.h index 1662c78a68..35fc078c3c 100644 --- a/irr/src/COpenGLExtensionHandler.h +++ b/irr/src/COpenGLExtensionHandler.h @@ -1207,9 +1207,6 @@ public: void extGlBindTextures(GLuint first, GLsizei count, const GLuint *textures, const GLenum *targets); void extGlGenerateTextureMipmap(GLuint texture, GLenum target); - // generic vsync setting method for several extensions - void extGlSwapInterval(int interval); - // the global feature array bool FeatureAvailable[IRR_OpenGL_Feature_Count]; @@ -1388,19 +1385,6 @@ protected: PFNGLNAMEDFRAMEBUFFERTEXTUREEXTPROC pGlNamedFramebufferTextureEXT; PFNGLFRAMEBUFFERTEXTUREPROC pGlFramebufferTexture; PFNGLGENERATETEXTUREMIPMAPEXTPROC pGlGenerateTextureMipmapEXT; - -#if defined(WGL_EXT_swap_control) - PFNWGLSWAPINTERVALEXTPROC pWglSwapIntervalEXT; -#endif -#if defined(GLX_SGI_swap_control) - PFNGLXSWAPINTERVALSGIPROC pGlxSwapIntervalSGI; -#endif -#if defined(GLX_EXT_swap_control) - PFNGLXSWAPINTERVALEXTPROC pGlxSwapIntervalEXT; -#endif -#if defined(GLX_MESA_swap_control) - PFNGLXSWAPINTERVALMESAPROC pGlxSwapIntervalMESA; -#endif }; inline void COpenGLExtensionHandler::irrGlActiveTexture(GLenum texture) @@ -2581,32 +2565,6 @@ inline void COpenGLExtensionHandler::extGlGenerateTextureMipmap(GLuint texture, } } -inline void COpenGLExtensionHandler::extGlSwapInterval(int interval) -{ - // we have wglext, so try to use that -#if defined(_IRR_WINDOWS_API_) && defined(_IRR_COMPILE_WITH_WINDOWS_DEVICE_) -#ifdef WGL_EXT_swap_control - if (pWglSwapIntervalEXT) - pWglSwapIntervalEXT(interval); -#endif -#endif -#ifdef _IRR_COMPILE_WITH_X11_DEVICE_ -#if defined(GLX_MESA_swap_control) - if (pGlxSwapIntervalMESA) - pGlxSwapIntervalMESA(interval); -#elif defined(GLX_EXT_swap_control) - Display *dpy = glXGetCurrentDisplay(); - GLXDrawable drawable = glXGetCurrentDrawable(); - if (pGlxSwapIntervalEXT) - pGlxSwapIntervalEXT(dpy, drawable, interval); -#elif defined(GLX_SGI_swap_control) - // does not work with interval==0 - if (interval && pGlxSwapIntervalSGI) - pGlxSwapIntervalSGI(interval); -} -#endif -#endif -} } #endif diff --git a/irr/src/CWGLManager.cpp b/irr/src/CWGLManager.cpp deleted file mode 100644 index b84ae16709..0000000000 --- a/irr/src/CWGLManager.cpp +++ /dev/null @@ -1,436 +0,0 @@ -// Copyright (C) 2013 Christian Stehno -// This file is part of the "Irrlicht Engine". -// For conditions of distribution and use, see copyright notice in Irrlicht.h - -#include "CWGLManager.h" - -#ifdef _IRR_COMPILE_WITH_WGL_MANAGER_ - -#include "os.h" - -#include -#include - -namespace video -{ - -CWGLManager::CWGLManager() : - PrimaryContext(SExposedVideoData(0)), PixelFormat(0), libHandle(NULL) -{ - memset(FunctionPointers, 0, sizeof(FunctionPointers)); -} - -CWGLManager::~CWGLManager() -{ -} - -bool CWGLManager::initialize(const SIrrlichtCreationParameters ¶ms, const SExposedVideoData &videodata) -{ - // store params, videoData is set later as it would be overwritten else - Params = params; - - // Create a window to test antialiasing support - const fschar_t *ClassName = __TEXT("CWGLManager"); - HINSTANCE lhInstance = GetModuleHandle(0); - - // Register Class - WNDCLASSEX wcex; - wcex.cbSize = sizeof(WNDCLASSEX); - wcex.style = CS_HREDRAW | CS_VREDRAW; - wcex.lpfnWndProc = (WNDPROC)DefWindowProc; - wcex.cbClsExtra = 0; - wcex.cbWndExtra = 0; - wcex.hInstance = lhInstance; - wcex.hIcon = 0; - wcex.hCursor = LoadCursor(NULL, IDC_ARROW); - wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1); - wcex.lpszMenuName = 0; - wcex.lpszClassName = ClassName; - wcex.hIconSm = 0; - RegisterClassEx(&wcex); - - RECT clientSize; - clientSize.top = 0; - clientSize.left = 0; - clientSize.right = Params.WindowSize.Width; - clientSize.bottom = Params.WindowSize.Height; - - DWORD style = WS_POPUP; - if (!Params.Fullscreen) - style = WS_SYSMENU | WS_BORDER | WS_CAPTION | WS_CLIPCHILDREN | WS_CLIPSIBLINGS; - - AdjustWindowRect(&clientSize, style, FALSE); - - const s32 realWidth = clientSize.right - clientSize.left; - const s32 realHeight = clientSize.bottom - clientSize.top; - - const s32 windowLeft = (GetSystemMetrics(SM_CXSCREEN) - realWidth) / 2; - const s32 windowTop = (GetSystemMetrics(SM_CYSCREEN) - realHeight) / 2; - - HWND temporary_wnd = CreateWindow(ClassName, __TEXT(""), style, windowLeft, - windowTop, realWidth, realHeight, NULL, NULL, lhInstance, NULL); - - if (!temporary_wnd) { - os::Printer::log("Cannot create a temporary window.", ELL_ERROR); - UnregisterClass(ClassName, lhInstance); - return false; - } - - HDC HDc = GetDC(temporary_wnd); - - // Set up pixel format descriptor with desired parameters - PIXELFORMATDESCRIPTOR tmp_pfd = { - sizeof(PIXELFORMATDESCRIPTOR), // Size Of This Pixel Format Descriptor - 1, // Version Number - (DWORD)(PFD_DRAW_TO_WINDOW | // Format Must Support Window - PFD_SUPPORT_OPENGL | // Format Must Support OpenGL - (Params.Doublebuffer ? PFD_DOUBLEBUFFER : 0) | // Must Support Double Buffering - (Params.Stereobuffer ? PFD_STEREO : 0)), // Must Support Stereo Buffer - PFD_TYPE_RGBA, // Request An RGBA Format - Params.Bits, // Select Our Color Depth - 0, 0, 0, 0, 0, 0, // Color Bits Ignored - 0, // No Alpha Buffer - 0, // Shift Bit Ignored - 0, // No Accumulation Buffer - 0, 0, 0, 0, // Accumulation Bits Ignored - Params.ZBufferBits, // Z-Buffer (Depth Buffer) - BYTE(Params.Stencilbuffer ? 1 : 0), // Stencil Buffer Depth - 0, // No Auxiliary Buffer - PFD_MAIN_PLANE, // Main Drawing Layer - 0, // Reserved - 0, 0, 0 // Layer Masks Ignored - }; - pfd = tmp_pfd; - - for (u32 i = 0; i < 6; ++i) { - if (i == 1) { - if (Params.Stencilbuffer) { - os::Printer::log("Cannot create a GL device with stencil buffer, disabling stencil shadows.", ELL_WARNING); - Params.Stencilbuffer = false; - pfd.cStencilBits = 0; - } else - continue; - } else if (i == 2) { - pfd.cDepthBits = 24; - } else if (i == 3) { - if (Params.Bits != 16) - pfd.cDepthBits = 16; - else - continue; - } else if (i == 4) { - // try single buffer - if (Params.Doublebuffer) - pfd.dwFlags &= ~PFD_DOUBLEBUFFER; - else - continue; - } else if (i == 5) { - os::Printer::log("Cannot create a GL device context", "No suitable format for temporary window.", ELL_ERROR); - ReleaseDC(temporary_wnd, HDc); - DestroyWindow(temporary_wnd); - UnregisterClass(ClassName, lhInstance); - return false; - } - - // choose pixelformat - PixelFormat = ChoosePixelFormat(HDc, &pfd); - if (PixelFormat) - break; - } - - SetPixelFormat(HDc, PixelFormat, &pfd); - os::Printer::log("Create temporary GL rendering context", ELL_DEBUG); - HGLRC hrc = wglCreateContext(HDc); - if (!hrc) { - os::Printer::log("Cannot create a temporary GL rendering context.", ELL_ERROR); - ReleaseDC(temporary_wnd, HDc); - DestroyWindow(temporary_wnd); - UnregisterClass(ClassName, lhInstance); - return false; - } - - CurrentContext.OpenGLWin32.HDc = HDc; - CurrentContext.OpenGLWin32.HRc = hrc; - CurrentContext.OpenGLWin32.HWnd = temporary_wnd; - - if (!activateContext(CurrentContext, false)) { - os::Printer::log("Cannot activate a temporary GL rendering context.", ELL_ERROR); - wglDeleteContext(hrc); - ReleaseDC(temporary_wnd, HDc); - DestroyWindow(temporary_wnd); - UnregisterClass(ClassName, lhInstance); - return false; - } - - core::stringc wglExtensions; -#ifdef WGL_ARB_extensions_string - PFNWGLGETEXTENSIONSSTRINGARBPROC irrGetExtensionsString = (PFNWGLGETEXTENSIONSSTRINGARBPROC)wglGetProcAddress("wglGetExtensionsStringARB"); - if (irrGetExtensionsString) - wglExtensions = irrGetExtensionsString(HDc); -#elif defined(WGL_EXT_extensions_string) - PFNWGLGETEXTENSIONSSTRINGEXTPROC irrGetExtensionsString = (PFNWGLGETEXTENSIONSSTRINGEXTPROC)wglGetProcAddress("wglGetExtensionsStringEXT"); - if (irrGetExtensionsString) - wglExtensions = irrGetExtensionsString(HDc); -#endif - const bool pixel_format_supported = (wglExtensions.find("WGL_ARB_pixel_format") != -1); - const bool multi_sample_supported = ((wglExtensions.find("WGL_ARB_multisample") != -1) || - (wglExtensions.find("WGL_EXT_multisample") != -1) || (wglExtensions.find("WGL_3DFX_multisample") != -1)); - if (params.DriverDebug) - os::Printer::log("WGL_extensions", wglExtensions); - - // Without a GL context we can't call wglGetProcAddress so store this for later - FunctionPointers[0] = (void *)wglGetProcAddress("wglCreateContextAttribsARB"); - -#ifdef WGL_ARB_pixel_format - PFNWGLCHOOSEPIXELFORMATARBPROC wglChoosePixelFormat_ARB = (PFNWGLCHOOSEPIXELFORMATARBPROC)wglGetProcAddress("wglChoosePixelFormatARB"); - if (pixel_format_supported && wglChoosePixelFormat_ARB) { - // This value determines the number of samples used for antialiasing - // My experience is that 8 does not show a big - // improvement over 4, but 4 shows a big improvement - // over 2. - - if (Params.AntiAlias > 32) - Params.AntiAlias = 32; - - f32 fAttributes[] = {0.0, 0.0}; - s32 iAttributes[] = { - WGL_DRAW_TO_WINDOW_ARB, 1, - WGL_SUPPORT_OPENGL_ARB, 1, - WGL_ACCELERATION_ARB, WGL_FULL_ACCELERATION_ARB, - WGL_COLOR_BITS_ARB, (Params.Bits == 32) ? 24 : 15, - WGL_ALPHA_BITS_ARB, (Params.Bits == 32) ? 8 : 1, - WGL_DEPTH_BITS_ARB, Params.ZBufferBits, // 10,11 - WGL_STENCIL_BITS_ARB, Params.Stencilbuffer ? 1 : 0, - WGL_DOUBLE_BUFFER_ARB, Params.Doublebuffer ? 1 : 0, - WGL_STEREO_ARB, Params.Stereobuffer ? 1 : 0, - WGL_PIXEL_TYPE_ARB, WGL_TYPE_RGBA_ARB, -#ifdef WGL_ARB_multisample - WGL_SAMPLES_ARB, Params.AntiAlias, // 20,21 - WGL_SAMPLE_BUFFERS_ARB, (Params.AntiAlias > 0) ? 1 : 0, -#elif defined(WGL_EXT_multisample) - WGL_SAMPLES_EXT, AntiAlias, // 20,21 - WGL_SAMPLE_BUFFERS_EXT, (Params.AntiAlias > 0) ? 1 : 0, -#elif defined(WGL_3DFX_multisample) - WGL_SAMPLES_3DFX, AntiAlias, // 20,21 - WGL_SAMPLE_BUFFERS_3DFX, (Params.AntiAlias > 0) ? 1 : 0, -#endif - // WGL_DEPTH_FLOAT_EXT, 1, - 0, 0, 0, 0, - }; - int iAttrSize = sizeof(iAttributes) / sizeof(int); - if (!multi_sample_supported) { - memmove(&iAttributes[20], &iAttributes[24], sizeof(int) * (iAttrSize - 24)); - iAttrSize -= 4; - } - - s32 rv = 0; - // Try to get an acceptable pixel format - do { - int pixelFormat = 0; - UINT numFormats = 0; - const BOOL valid = wglChoosePixelFormat_ARB(HDc, iAttributes, fAttributes, 1, &pixelFormat, &numFormats); - - if (valid && numFormats) - rv = pixelFormat; - else - iAttributes[21] -= 1; - } while (rv == 0 && iAttributes[21] > 1); - if (rv) { - PixelFormat = rv; - Params.AntiAlias = iAttributes[21]; - } - } else -#endif - Params.AntiAlias = 0; - - // this only terminates the temporary HRc - destroyContext(); - destroySurface(); - terminate(); - DestroyWindow(temporary_wnd); - UnregisterClass(ClassName, lhInstance); - - // now get new window - CurrentContext.OpenGLWin32.HWnd = videodata.OpenGLWin32.HWnd; - // get hdc - if (!(CurrentContext.OpenGLWin32.HDc = GetDC((HWND)videodata.OpenGLWin32.HWnd))) { - os::Printer::log("Cannot create a GL device context.", ELL_ERROR); - return false; - } - if (!PrimaryContext.OpenGLWin32.HWnd) { - PrimaryContext.OpenGLWin32.HWnd = CurrentContext.OpenGLWin32.HWnd; - PrimaryContext.OpenGLWin32.HDc = CurrentContext.OpenGLWin32.HDc; - } - - return true; -} - -void CWGLManager::terminate() -{ - if (CurrentContext.OpenGLWin32.HDc) - ReleaseDC((HWND)CurrentContext.OpenGLWin32.HWnd, (HDC)CurrentContext.OpenGLWin32.HDc); - if (PrimaryContext.OpenGLWin32.HDc && PrimaryContext.OpenGLWin32.HDc == CurrentContext.OpenGLWin32.HDc) - memset(&PrimaryContext, 0, sizeof(PrimaryContext)); - memset(&CurrentContext, 0, sizeof(CurrentContext)); - if (libHandle) - FreeLibrary(libHandle); -} - -bool CWGLManager::generateSurface() -{ - HDC HDc = (HDC)CurrentContext.OpenGLWin32.HDc; - // search for pixel format the simple way - if (PixelFormat == 0 || (!SetPixelFormat(HDc, PixelFormat, &pfd))) { - for (u32 i = 0; i < 5; ++i) { - if (i == 1) { - if (Params.Stencilbuffer) { - os::Printer::log("Cannot create a GL device with stencil buffer, disabling stencil shadows.", ELL_WARNING); - Params.Stencilbuffer = false; - pfd.cStencilBits = 0; - } else - continue; - } else if (i == 2) { - pfd.cDepthBits = 24; - } - if (i == 3) { - if (Params.Bits != 16) - pfd.cDepthBits = 16; - else - continue; - } else if (i == 4) { - os::Printer::log("Cannot create a GL device context", "No suitable format.", ELL_ERROR); - return false; - } - - // choose pixelformat - PixelFormat = ChoosePixelFormat(HDc, &pfd); - if (PixelFormat) - break; - } - - // set pixel format - if (!SetPixelFormat(HDc, PixelFormat, &pfd)) { - os::Printer::log("Cannot set the pixel format.", ELL_ERROR); - return false; - } - } - - if (pfd.cAlphaBits != 0) { - if (pfd.cRedBits == 8) - ColorFormat = ECF_A8R8G8B8; - else - ColorFormat = ECF_A1R5G5B5; - } else { - if (pfd.cRedBits == 8) - ColorFormat = ECF_R8G8B8; - else - ColorFormat = ECF_R5G6B5; - } - os::Printer::log("Pixel Format", core::stringc(PixelFormat).c_str(), ELL_DEBUG); - return true; -} - -void CWGLManager::destroySurface() -{ -} - -bool CWGLManager::generateContext() -{ - HDC HDc = (HDC)CurrentContext.OpenGLWin32.HDc; - HGLRC hrc; - // create rendering context -#ifdef WGL_ARB_create_context - PFNWGLCREATECONTEXTATTRIBSARBPROC wglCreateContextAttribs_ARB = (PFNWGLCREATECONTEXTATTRIBSARBPROC)FunctionPointers[0]; - if (wglCreateContextAttribs_ARB) { - // with 3.0 all available profiles should be usable, higher versions impose restrictions - // we need at least 1.1 - const int iAttribs[] = { - WGL_CONTEXT_MAJOR_VERSION_ARB, 1, - WGL_CONTEXT_MINOR_VERSION_ARB, 1, - // WGL_CONTEXT_FLAGS_ARB, WGL_CONTEXT_DEBUG_BIT_ARB, // enable to get a debug context (depends on driver if that does anything) - 0, - }; - hrc = wglCreateContextAttribs_ARB(HDc, 0, iAttribs); - } else -#endif - hrc = wglCreateContext(HDc); - os::Printer::log("Irrlicht context"); - - if (!hrc) { - os::Printer::log("Cannot create a GL rendering context.", ELL_ERROR); - return false; - } - - // set exposed data - CurrentContext.OpenGLWin32.HRc = hrc; - if (!PrimaryContext.OpenGLWin32.HRc) - PrimaryContext.OpenGLWin32.HRc = CurrentContext.OpenGLWin32.HRc; - - return true; -} - -const SExposedVideoData &CWGLManager::getContext() const -{ - return CurrentContext; -} - -bool CWGLManager::activateContext(const SExposedVideoData &videoData, bool restorePrimaryOnZero) -{ - if (videoData.OpenGLWin32.HWnd && videoData.OpenGLWin32.HDc && videoData.OpenGLWin32.HRc) { - if (!wglMakeCurrent((HDC)videoData.OpenGLWin32.HDc, (HGLRC)videoData.OpenGLWin32.HRc)) { - os::Printer::log("Render Context switch failed."); - return false; - } - CurrentContext = videoData; - } else if (!restorePrimaryOnZero && !videoData.OpenGLWin32.HDc && !videoData.OpenGLWin32.HRc) { - if (!wglMakeCurrent((HDC)0, (HGLRC)0)) { - os::Printer::log("Render Context reset failed."); - return false; - } - CurrentContext = videoData; - } - // set back to main context - else if (!videoData.OpenGLWin32.HWnd && CurrentContext.OpenGLWin32.HDc != PrimaryContext.OpenGLWin32.HDc) { - if (!wglMakeCurrent((HDC)PrimaryContext.OpenGLWin32.HDc, (HGLRC)PrimaryContext.OpenGLWin32.HRc)) { - os::Printer::log("Render Context switch (back to main) failed."); - return false; - } - CurrentContext = PrimaryContext; - } - return true; -} - -void CWGLManager::destroyContext() -{ - if (CurrentContext.OpenGLWin32.HRc) { - if (!wglMakeCurrent((HDC)CurrentContext.OpenGLWin32.HDc, 0)) - os::Printer::log("Release of render context failed.", ELL_WARNING); - - if (!wglDeleteContext((HGLRC)CurrentContext.OpenGLWin32.HRc)) - os::Printer::log("Deletion of render context failed.", ELL_WARNING); - if (PrimaryContext.OpenGLWin32.HRc == CurrentContext.OpenGLWin32.HRc) - PrimaryContext.OpenGLWin32.HRc = 0; - CurrentContext.OpenGLWin32.HRc = 0; - } -} - -void *CWGLManager::getProcAddress(const std::string &procName) -{ - void *proc = NULL; - proc = (void *)wglGetProcAddress(procName.c_str()); - if (!proc) { // Fallback - if (!libHandle) - libHandle = LoadLibraryA("opengl32.dll"); - if (libHandle) - proc = (void *)GetProcAddress(libHandle, procName.c_str()); - } - return proc; -} - -bool CWGLManager::swapBuffers() -{ - return SwapBuffers((HDC)CurrentContext.OpenGLWin32.HDc) == TRUE; -} - -} - -#endif diff --git a/irr/src/CWGLManager.h b/irr/src/CWGLManager.h deleted file mode 100644 index 390e561a61..0000000000 --- a/irr/src/CWGLManager.h +++ /dev/null @@ -1,73 +0,0 @@ -// Copyright (C) 2013 Christian Stehno -// This file is part of the "Irrlicht Engine". -// For conditions of distribution and use, see copyright notice in Irrlicht.h - -#pragma once - -#ifdef _IRR_COMPILE_WITH_WGL_MANAGER_ - -#include "SIrrCreationParameters.h" -#include "SExposedVideoData.h" -#include "IContextManager.h" -#include "SColor.h" - -#define WIN32_LEAN_AND_MEAN -#include -#include - -namespace video -{ -// WGL manager. -class CWGLManager : public IContextManager -{ -public: - //! Constructor. - CWGLManager(); - - //! Destructor - ~CWGLManager(); - - // Initialize - bool initialize(const SIrrlichtCreationParameters ¶ms, const SExposedVideoData &data) override; - - // Terminate - void terminate() override; - - // Create surface. - bool generateSurface() override; - - // Destroy surface. - void destroySurface() override; - - // Create context. - bool generateContext() override; - - // Destroy EGL context. - void destroyContext() override; - - //! Get current context - const SExposedVideoData &getContext() const override; - - //! Change render context, disable old and activate new defined by videoData - bool activateContext(const SExposedVideoData &videoData, bool restorePrimaryOnZero) override; - - // Get procedure address. - void *getProcAddress(const std::string &procName) override; - - // Swap buffers. - bool swapBuffers() override; - -private: - SIrrlichtCreationParameters Params; - SExposedVideoData PrimaryContext; - SExposedVideoData CurrentContext; - s32 PixelFormat; - PIXELFORMATDESCRIPTOR pfd; - ECOLOR_FORMAT ColorFormat; - void *FunctionPointers[1]; - - HMODULE libHandle; -}; -} - -#endif diff --git a/irr/src/Irrlicht.cpp b/irr/src/Irrlicht.cpp index 86206dbd8f..eb8aba5c75 100644 --- a/irr/src/Irrlicht.cpp +++ b/irr/src/Irrlicht.cpp @@ -8,18 +8,6 @@ static const char *const copyright = "Irrlicht Engine (c) 2002-2017 Nikolaus Geb #include "matrix4.h" #include "SMaterial.h" -#ifdef _IRR_COMPILE_WITH_WINDOWS_DEVICE_ -#include "CIrrDeviceWin32.h" -#endif - -#ifdef _IRR_COMPILE_WITH_X11_DEVICE_ -#include "CIrrDeviceLinux.h" -#endif - -#ifdef _IRR_COMPILE_WITH_OSX_DEVICE_ -#include "CIrrDeviceOSX.h" -#endif - #ifdef _IRR_COMPILE_WITH_SDL_DEVICE_ #include "CIrrDeviceSDL.h" #endif @@ -49,21 +37,6 @@ extern "C" IrrlichtDevice *createDeviceEx(const SIrrlichtCreationParameters &par IrrlichtDevice *dev = 0; -#ifdef _IRR_COMPILE_WITH_WINDOWS_DEVICE_ - if (params.DeviceType == EIDT_WIN32 || (!dev && params.DeviceType == EIDT_BEST)) - dev = new CIrrDeviceWin32(params); -#endif - -#ifdef _IRR_COMPILE_WITH_OSX_DEVICE_ - if (params.DeviceType == EIDT_OSX || (!dev && params.DeviceType == EIDT_BEST)) - dev = new CIrrDeviceMacOSX(params); -#endif - -#ifdef _IRR_COMPILE_WITH_X11_DEVICE_ - if (params.DeviceType == EIDT_X11 || (!dev && params.DeviceType == EIDT_BEST)) - dev = new CIrrDeviceLinux(params); -#endif - #ifdef _IRR_COMPILE_WITH_SDL_DEVICE_ if (params.DeviceType == EIDT_SDL || (!dev && params.DeviceType == EIDT_BEST)) dev = new CIrrDeviceSDL(params); diff --git a/src/client/game.cpp b/src/client/game.cpp index d88385f6b9..5b86883446 100644 --- a/src/client/game.cpp +++ b/src/client/game.cpp @@ -2049,10 +2049,10 @@ void Game::updateCameraDirection(CameraOrientation *cam, float dtime) { auto *cur_control = device->getCursorControl(); - /* With CIrrDeviceSDL on Linux and Windows, enabling relative mouse mode - somehow results in simulated mouse events being generated from touch events, - although SDL_HINT_MOUSE_TOUCH_EVENTS and SDL_HINT_TOUCH_MOUSE_EVENTS are set to 0. - Since Minetest has its own code to synthesize mouse events from touch events, + /* On Linux and Windows, enabling relative mouse mode somehow results + in simulated mouse events being generated from touch events, even though + SDL_HINT_MOUSE_TOUCH_EVENTS and SDL_HINT_TOUCH_MOUSE_EVENTS are set to 0. + Since we have our own code to synthesize mouse events from touch events, this results in duplicated input. To avoid that, we don't enable relative mouse mode if we're in touchscreen mode. */ if (cur_control) diff --git a/src/client/inputhandler.cpp b/src/client/inputhandler.cpp index 52e73356cb..9f7e0c36fe 100644 --- a/src/client/inputhandler.cpp +++ b/src/client/inputhandler.cpp @@ -143,8 +143,7 @@ bool MyEventReceiver::OnEvent(const SEvent &event) IrrlichtDevice *device = RenderingEngine::get_raw_device(); bool new_fullscreen = !device->isFullscreen(); - // Only update the setting if toggling succeeds - it always fails - // if Minetest was built without SDL. + // Only update the setting if toggling succeeds if (device->setFullscreen(new_fullscreen)) { g_settings->setBool("fullscreen", new_fullscreen); } diff --git a/src/client/keycode.cpp b/src/client/keycode.cpp index 50adcca889..f2f0d77585 100644 --- a/src/client/keycode.cpp +++ b/src/client/keycode.cpp @@ -305,31 +305,24 @@ KeyPress::KeyPress(const std::string &name) KeyPress::KeyPress(const SEvent::SKeyInput &in) { - if (USE_SDL2) { - if (in.SystemKeyCode) - scancode.emplace(in.SystemKeyCode); - else - scancode.emplace(in.Key); - } else { - loadFromKey(in.Key, in.Char); - } + if (in.SystemKeyCode) + scancode.emplace(in.SystemKeyCode); + else + scancode.emplace(in.Key); } std::string KeyPress::formatScancode() const { - if (USE_SDL2) { - if (auto pv = std::get_if(&scancode)) - return *pv == 0 ? "" : "SYSTEM_SCANCODE_" + std::to_string(*pv); - } + if (auto pv = std::get_if(&scancode)) + return *pv == 0 ? "" : "SYSTEM_SCANCODE_" + std::to_string(*pv); return ""; } std::string KeyPress::sym() const { std::string name = lookup_scancode(scancode).Name; - if (USE_SDL2 || name.empty()) - if (auto newname = formatScancode(); !newname.empty()) - return newname; + if (auto newname = formatScancode(); !newname.empty()) + return newname; return name; } @@ -353,18 +346,14 @@ wchar_t KeyPress::getKeychar() const bool KeyPress::loadFromScancode(const std::string &name) { - if (USE_SDL2) { - if (!str_starts_with(name, "SYSTEM_SCANCODE_")) - return false; - char *p; - const auto code = strtoul(name.c_str()+16, &p, 10); - if (p != name.c_str() + name.size()) - return false; - scancode.emplace(code); - return true; - } else { + if (!str_starts_with(name, "SYSTEM_SCANCODE_")) return false; - } + char *p; + const auto code = strtoul(name.c_str()+16, &p, 10); + if (p != name.c_str() + name.size()) + return false; + scancode.emplace(code); + return true; } std::unordered_map specialKeyCache; diff --git a/src/cmake_config.h.in b/src/cmake_config.h.in index 2ec91dfd11..eef87e6877 100644 --- a/src/cmake_config.h.in +++ b/src/cmake_config.h.in @@ -41,5 +41,4 @@ #cmakedefine01 CURSES_HAVE_NCURSESW_CURSES_H #cmakedefine01 BUILD_UNITTESTS #cmakedefine01 BUILD_BENCHMARKS -#cmakedefine01 USE_SDL2 #cmakedefine01 BUILD_WITH_TRACY diff --git a/src/defaultsettings.cpp b/src/defaultsettings.cpp index 4068f776ec..4008d2af6f 100644 --- a/src/defaultsettings.cpp +++ b/src/defaultsettings.cpp @@ -129,23 +129,14 @@ void set_default_settings() settings->setDefault("chat_weblink_color", "#8888FF"); // Keymap -#if USE_SDL2 #define USEKEY2(name, value, _) settings->setDefault(name, value) -#else -#define USEKEY2(name, _, value) settings->setDefault(name, value) -#endif USEKEY2("keymap_forward", "SYSTEM_SCANCODE_26", "KEY_KEY_W"); settings->setDefault("keymap_autoforward", ""); USEKEY2("keymap_backward", "SYSTEM_SCANCODE_22", "KEY_KEY_S"); USEKEY2("keymap_left", "SYSTEM_SCANCODE_4", "KEY_KEY_A"); USEKEY2("keymap_right", "SYSTEM_SCANCODE_7", "KEY_KEY_D"); USEKEY2("keymap_jump", "SYSTEM_SCANCODE_44", "KEY_SPACE"); -#if !USE_SDL2 && defined(__MACH__) && defined(__APPLE__) - // Altered settings for CIrrDeviceOSX - settings->setDefault("keymap_sneak", "KEY_SHIFT"); -#else USEKEY2("keymap_sneak", "SYSTEM_SCANCODE_225", "KEY_LSHIFT"); -#endif settings->setDefault("keymap_dig", "KEY_LBUTTON"); settings->setDefault("keymap_place", "KEY_RBUTTON"); USEKEY2("keymap_drop", "SYSTEM_SCANCODE_20", "KEY_KEY_Q");