From 34b6bda23305e1b29e539f671bbc42a4c554f7c4 Mon Sep 17 00:00:00 2001 From: Andrew Mickelson Date: Wed, 17 Jul 2024 20:15:09 -0700 Subject: [PATCH 1/4] [drm] Fix DRM mode setting to use SFML window dimensions - actually use the dimensions of the SFML window as the DRM mode dimensions when setting a DRM mode. - If SFML window dimensions don't match a valid DRM mode, show the window contents on screen in the current mode instead of simply failing to show anything. - With these change the SFML examples are now working for me --- src/SFML/Window/DRM/DRMContext.cpp | 202 +++++++++++++------------- src/SFML/Window/DRM/DRMContext.hpp | 8 +- src/SFML/Window/DRM/VideoModeImpl.cpp | 3 + 3 files changed, 109 insertions(+), 104 deletions(-) diff --git a/src/SFML/Window/DRM/DRMContext.cpp b/src/SFML/Window/DRM/DRMContext.cpp index fa6d96d9d..a8edee2b3 100644 --- a/src/SFML/Window/DRM/DRMContext.cpp +++ b/src/SFML/Window/DRM/DRMContext.cpp @@ -297,11 +297,13 @@ namespace if (fileDescriptor < 0) continue; result = getResources(fileDescriptor, resources); + if (!result && hasMonitorConnected(fileDescriptor, *resources) != 0) + { #ifdef SFML_DEBUG - sf::err() << "DRM device used: " << i << std::endl; + sf::err() << "DRM device used: " << device->nodes[DRM_NODE_PRIMARY] << std::endl; #endif - if(!result && hasMonitorConnected(fileDescriptor, *resources) != 0) break; + } close(fileDescriptor); fileDescriptor = -1; } @@ -312,23 +314,28 @@ namespace return fileDescriptor; } - int initDrm(sf::priv::Drm& drm, const char* device, const char* modeStr, unsigned int vrefresh) + int initDrm() { + if (initialized) + return 0; + drmModeResPtr resources; - if (device) + // Use environment variable "SFML_DRM_DEVICE" (or NULL if not set) + char* deviceStr = std::getenv("SFML_DRM_DEVICE"); + if (deviceStr && *deviceStr) { - drm.fileDescriptor = open(device, O_RDWR); - const int ret = getResources(drm.fileDescriptor, resources); + drmNode.fileDescriptor = open(deviceStr, O_RDWR); + const int ret = getResources(drmNode.fileDescriptor, resources); if (ret < 0 && errno == EOPNOTSUPP) - sf::err() << device << " does not look like a modeset device" << std::endl; + sf::err() << deviceStr << " does not look like a modeset device" << std::endl; } else { - drm.fileDescriptor = findDrmDevice(resources); + drmNode.fileDescriptor = findDrmDevice(resources); } - if (drm.fileDescriptor < 0) + if (drmNode.fileDescriptor < 0) { sf::err() << "Could not open drm device" << std::endl; return -1; @@ -344,7 +351,7 @@ namespace drmModeConnectorPtr connector = NULL; for (int i = 0; i < resources->count_connectors; ++i) { - connector = drmModeGetConnector(drm.fileDescriptor, resources->connectors[i]); + connector = drmModeGetConnector(drmNode.fileDescriptor, resources->connectors[i]); if (connector->connection == DRM_MODE_CONNECTED) { // It's connected, let's use this! @@ -361,31 +368,11 @@ namespace return -1; } - // Find user requested mode: - if (modeStr && *modeStr) - { - for (int i = 0; i < connector->count_modes; ++i) - { - drmModeModeInfoPtr currentMode = &connector->modes[i]; - - if (std::strcmp(currentMode->name, modeStr) == 0) - { - if (vrefresh == 0 || currentMode->vrefresh == vrefresh) - { - drm.mode = currentMode; - break; - } - } - } - if (!drm.mode) - sf::err() << "Requested mode not found, using default mode!" << std::endl; - } - // Find encoder: drmModeEncoderPtr encoder = NULL; for (int i = 0; i < resources->count_encoders; ++i) { - encoder = drmModeGetEncoder(drm.fileDescriptor, resources->encoders[i]); + encoder = drmModeGetEncoder(drmNode.fileDescriptor, resources->encoders[i]); if (encoder->encoder_id == connector->encoder_id) break; drmModeFreeEncoder(encoder); @@ -394,56 +381,56 @@ namespace if (encoder) { - drm.crtcId = encoder->crtc_id; + drmNode.crtcId = encoder->crtc_id; } else { - const sf::Uint32 crtcId = findCrtcForConnector(drm, *resources, *connector); + const sf::Uint32 crtcId = findCrtcForConnector(drmNode, *resources, *connector); if (crtcId == 0) { sf::err() << "No crtc found!" << std::endl; return -1; } - drm.crtcId = crtcId; + drmNode.crtcId = crtcId; } drmModeFreeResources(resources); - drm.connectorId = connector->connector_id; + drmNode.connectorId = connector->connector_id; - drm.savedConnector = connector; - drm.savedEncoder = encoder; + drmNode.savedConnector = connector; + drmNode.savedEncoder = encoder; // Get original display mode so we can restore display mode after program exits - drm.originalCrtc = drmModeGetCrtc(drm.fileDescriptor, drm.crtcId); + drmNode.originalCrtc = drmModeGetCrtc(drmNode.fileDescriptor, drmNode.crtcId); - // Let's use the current mode rather than the preferred one if the user didn't specify a mode with env vars - if (!drm.mode) - { -#ifdef SFML_DEBUG - sf::err() << "DRM using the current mode" << std::endl; -#endif - drm.mode = &(drm.originalCrtc->mode); - } + gbmDevice = gbm_create_device(drmNode.fileDescriptor); -#ifdef SFML_DEBUG - sf::err() << "DRM Mode used: " << drm.mode->name << "@" << drm.mode->vrefresh << std::endl; -#endif + std::atexit(cleanup); + initialized = true; - return 0; + pollFD.fd = drmNode.fileDescriptor; + pollFD.events = POLLIN; + drmEventCtx.version = 2; + drmEventCtx.page_flip_handler = pageFlipHandler; + + drmNode.mode = 0; + + return 1; } - void checkInit() + void setDrmMode( unsigned int width=0, unsigned int height=0 ) { - if (initialized) + // don't do anything if supplied width and height are 0 and we already have a drm mode + if (( width == 0 ) && drmNode.mode ) return; - // Use environment variable "SFML_DRM_DEVICE" (or NULL if not set) - char* deviceString = std::getenv("SFML_DRM_DEVICE"); - if (deviceString && !*deviceString) - deviceString = NULL; + drmModeConnectorPtr connector = drmNode.savedConnector; + if (!connector) + return; + // Find user requested mode: // Use environment variable "SFML_DRM_MODE" (or NULL if not set) char* modeString = std::getenv("SFML_DRM_MODE"); @@ -456,30 +443,41 @@ namespace if (refreshString) refreshRate = static_cast(atoi(refreshString)); - if (initDrm(drmNode, - deviceString, // device - modeString, // requested mode - refreshRate) < 0) // screen refresh rate + bool matched = false; + for (int i = 0; i < connector->count_modes; ++i) { - sf::err() << "Error initializing DRM" << std::endl; - return; + drmModeModeInfoPtr currentMode = &connector->modes[i]; + + if (refreshRate == 0 || currentMode->vrefresh == refreshRate) + { + // prefer SFML_DRM_MODE setting if matched + if ((modeString && *modeString) && (std::strcmp(currentMode->name, modeString) == 0)) + { + drmNode.mode = currentMode; + break; + } + // otherwise match to program supplied width and height + if (!matched && ( currentMode->hdisplay == width ) && ( currentMode->vdisplay == height )) + { + drmNode.mode = currentMode; + matched=true; + } + } } + if ((modeString && *modeString) && !drmNode.mode) + sf::err() << "SFML_DRM_MODE (" << modeString << ") not found, using default mode!" << std::endl; - gbmDevice = gbm_create_device(drmNode.fileDescriptor); + // Let's use the current mode rather than the preferred one if the user didn't specify a mode with env vars + if (!drmNode.mode) + drmNode.mode = &(drmNode.originalCrtc->mode); - std::atexit(cleanup); - initialized = true; - - pollFD.fd = drmNode.fileDescriptor; - pollFD.events = POLLIN; - drmEventCtx.version = 2; - drmEventCtx.page_flip_handler = pageFlipHandler; +#ifdef SFML_DEBUG + sf::err() << "DRM Mode used: " << drmNode.mode->name << "@" << drmNode.mode->vrefresh << std::endl; +#endif } EGLDisplay getInitializedDisplay() { - checkInit(); - if (display == EGL_NO_DISPLAY) { gladLoaderLoadEGL(EGL_NO_DISPLAY); @@ -522,32 +520,34 @@ m_config (NULL), m_currentBO (NULL), m_nextBO (NULL), m_gbmSurface (NULL), -m_width (0), -m_height (0), m_shown (false), m_scanOut (false) { contextCount++; + if (initDrm() < 0) + return; + + setDrmMode(); // Get the initialized EGL display m_display = getInitializedDisplay(); // Get the best EGL config matching the default video settings - m_config = getBestConfig(m_display, VideoMode::getDesktopMode().bitsPerPixel, ContextSettings()); + m_config = getBestConfig(m_display, ContextSettings()); updateSettings(); // Create EGL context createContext(shared); if (shared) - createSurface(shared->m_width, shared->m_height, VideoMode::getDesktopMode().bitsPerPixel, false); + createSurface(drmNode.mode->hdisplay, drmNode.mode->vdisplay, false); else // create a surface to force the GL to initialize (seems to be required for glGetString() etc ) - createSurface(1, 1, VideoMode::getDesktopMode().bitsPerPixel, false); + createSurface(1, 1, false); } //////////////////////////////////////////////////////////// -DRMContext::DRMContext(DRMContext* shared, const ContextSettings& settings, const WindowImpl* owner, unsigned int bitsPerPixel) : +DRMContext::DRMContext(DRMContext* shared, const ContextSettings& settings, const WindowImpl* owner, unsigned int /*bitsPerPixel*/) : m_display (EGL_NO_DISPLAY), m_context (EGL_NO_CONTEXT), m_surface (EGL_NO_SURFACE), @@ -555,33 +555,37 @@ m_config (NULL), m_currentBO (NULL), m_nextBO (NULL), m_gbmSurface (NULL), -m_width (0), -m_height (0), m_shown (false), m_scanOut (false) { contextCount++; + if (initDrm() < 0) + return; + + Vector2u size; + if (owner) + size = owner->getSize(); + + setDrmMode(size.x, size.y); + // Get the initialized EGL display m_display = getInitializedDisplay(); // Get the best EGL config matching the requested video settings - m_config = getBestConfig(m_display, bitsPerPixel, settings); + m_config = getBestConfig(m_display, settings); updateSettings(); // Create EGL context createContext(shared); if (owner) - { - Vector2u size = owner->getSize(); - createSurface(size.x, size.y, bitsPerPixel, true); - } + createSurface(drmNode.mode->hdisplay, drmNode.mode->vdisplay, true); } //////////////////////////////////////////////////////////// -DRMContext::DRMContext(DRMContext* shared, const ContextSettings& settings, unsigned int width, unsigned int height) : +DRMContext::DRMContext(DRMContext* shared, const ContextSettings& settings, unsigned int /*width*/, unsigned int /*height*/) : m_display (EGL_NO_DISPLAY), m_context (EGL_NO_CONTEXT), m_surface (EGL_NO_SURFACE), @@ -589,23 +593,25 @@ m_config (NULL), m_currentBO (NULL), m_nextBO (NULL), m_gbmSurface (NULL), -m_width (0), -m_height (0), m_shown (false), m_scanOut (false) { contextCount++; + if (initDrm() < 0) + return; + + setDrmMode(); // Get the initialized EGL display m_display = getInitializedDisplay(); // Get the best EGL config matching the requested video settings - m_config = getBestConfig(m_display, VideoMode::getDesktopMode().bitsPerPixel, settings); + m_config = getBestConfig(m_display, settings); updateSettings(); // Create EGL context createContext(shared); - createSurface(width, height, VideoMode::getDesktopMode().bitsPerPixel, false); + createSurface(drmNode.mode->hdisplay, drmNode.mode->vdisplay, false); } @@ -751,19 +757,23 @@ void DRMContext::createContext(DRMContext* shared) //////////////////////////////////////////////////////////// -void DRMContext::createSurface(unsigned int width, unsigned int height, unsigned int /*bpp*/, bool scanout) +void DRMContext::createSurface(unsigned int width, unsigned int height, bool scanout) { sf::Uint32 flags = GBM_BO_USE_RENDERING; + uint32_t fmt = GBM_FORMAT_ARGB8888; m_scanOut = scanout; if (m_scanOut) flags |= GBM_BO_USE_SCANOUT; + if (!gbm_device_is_format_supported(gbmDevice, fmt, flags)) + err() << "Warning: GBM surface format not supported." << std::endl; + m_gbmSurface = gbm_surface_create( gbmDevice, width, height, - GBM_FORMAT_ARGB8888, + fmt, flags); if (!m_gbmSurface) @@ -772,9 +782,6 @@ void DRMContext::createSurface(unsigned int width, unsigned int height, unsigned return; } - m_width = width; - m_height = height; - eglCheck(m_surface = eglCreateWindowSurface(m_display, m_config, reinterpret_cast(m_gbmSurface), NULL)); if (m_surface == EGL_NO_SURFACE) @@ -799,12 +806,11 @@ void DRMContext::destroySurface() //////////////////////////////////////////////////////////// -EGLConfig DRMContext::getBestConfig(EGLDisplay display, unsigned int bitsPerPixel, const ContextSettings& settings) +EGLConfig DRMContext::getBestConfig(EGLDisplay display, const ContextSettings& settings) { // Set our video settings constraint const EGLint attributes[] = { - EGL_BUFFER_SIZE, static_cast(bitsPerPixel), EGL_DEPTH_SIZE, static_cast(settings.depthBits), EGL_STENCIL_SIZE, static_cast(settings.stencilBits), EGL_SAMPLE_BUFFERS, static_cast(settings.antialiasingLevel), @@ -863,7 +869,7 @@ GlFunctionPointer DRMContext::getFunction(const char* name) //////////////////////////////////////////////////////////// Drm& DRMContext::getDRM() { - checkInit(); + initDrm(); return drmNode; } diff --git a/src/SFML/Window/DRM/DRMContext.hpp b/src/SFML/Window/DRM/DRMContext.hpp index 6a944d585..45211240c 100644 --- a/src/SFML/Window/DRM/DRMContext.hpp +++ b/src/SFML/Window/DRM/DRMContext.hpp @@ -143,11 +143,10 @@ public: /// /// \param width Back buffer width, in pixels /// \param height Back buffer height, in pixels - /// \param bpp Pixel depth, in bits per pixel /// \param scanout True to present the surface to the screen /// //////////////////////////////////////////////////////////// - void createSurface(unsigned int width, unsigned int height, unsigned int bpp, bool scanout); + void createSurface(unsigned int width, unsigned int height, bool scanout); //////////////////////////////////////////////////////////// /// \brief Destroy the EGL surface @@ -162,13 +161,12 @@ public: /// \brief Get the best EGL visual for a given set of video settings /// /// \param display EGL display - /// \param bitsPerPixel Pixel depth, in bits per pixel /// \param settings Requested context settings /// /// \return The best EGL config /// //////////////////////////////////////////////////////////// - static EGLConfig getBestConfig(EGLDisplay display, unsigned int bitsPerPixel, const ContextSettings& settings); + static EGLConfig getBestConfig(EGLDisplay display, const ContextSettings& settings); //////////////////////////////////////////////////////////// /// \brief Get the address of an OpenGL function @@ -210,8 +208,6 @@ private: gbm_bo* m_currentBO; gbm_bo* m_nextBO; gbm_surface* m_gbmSurface; - unsigned int m_width; - unsigned int m_height; bool m_shown; bool m_scanOut; }; diff --git a/src/SFML/Window/DRM/VideoModeImpl.cpp b/src/SFML/Window/DRM/VideoModeImpl.cpp index cdd6d92e8..47dc0bd2d 100644 --- a/src/SFML/Window/DRM/VideoModeImpl.cpp +++ b/src/SFML/Window/DRM/VideoModeImpl.cpp @@ -61,6 +61,9 @@ VideoMode VideoModeImpl::getDesktopMode() { Drm& drm = sf::priv::DRMContext::getDRM(); drmModeModeInfoPtr ptr = drm.mode; + if (!ptr) // if no mode has been set, return the original mode we started with + ptr = &drm.originalCrtc->mode; + if (ptr) return VideoMode(ptr->hdisplay, ptr->vdisplay); else From 15e001608a48e22fce24e2d8eba9ef193c294d23 Mon Sep 17 00:00:00 2001 From: acsbendi Date: Wed, 20 Feb 2019 19:21:31 +0100 Subject: [PATCH 2/4] Fixed wrong fullscreen resolution --- src/SFML/Main/MainAndroid.cpp | 43 +++++++++++++++++++++++ src/SFML/System/Android/Activity.hpp | 1 + src/SFML/Window/Android/VideoModeImpl.cpp | 10 +++++- 3 files changed, 53 insertions(+), 1 deletion(-) diff --git a/src/SFML/Main/MainAndroid.cpp b/src/SFML/Main/MainAndroid.cpp index 2f70c3083..37580f6b6 100644 --- a/src/SFML/Main/MainAndroid.cpp +++ b/src/SFML/Main/MainAndroid.cpp @@ -243,6 +243,48 @@ void getScreenSizeInPixels(ANativeActivity* activity, int* width, int* height) } +//////////////////////////////////////////////////////////// +void getFullScreenSizeInPixels(ANativeActivity* activity, int* width, int* height) +{ + // Perform the following Java code: + // + // DisplayMetrics dm = new DisplayMetrics(); + // getWindowManager().getDefaultDisplay().getRealMetrics(dm); + + JNIEnv* lJNIEnv = activity->env; + + jobject objectActivity = activity->clazz; + jclass classActivity = lJNIEnv->GetObjectClass(objectActivity); + + jclass classDisplayMetrics = lJNIEnv->FindClass("android/util/DisplayMetrics"); + jmethodID initDisplayMetrics = lJNIEnv->GetMethodID(classDisplayMetrics, "", "()V"); + jobject objectDisplayMetrics = lJNIEnv->NewObject(classDisplayMetrics, initDisplayMetrics); + + jmethodID methodGetWindowManager = lJNIEnv->GetMethodID(classActivity, "getWindowManager", "()Landroid/view/WindowManager;"); + jobject objectWindowManager = lJNIEnv->CallObjectMethod(objectActivity, methodGetWindowManager); + + jclass classWindowManager = lJNIEnv->FindClass("android/view/WindowManager"); + jmethodID methodGetDefaultDisplay = lJNIEnv->GetMethodID(classWindowManager, "getDefaultDisplay", "()Landroid/view/Display;"); + jobject objectDisplay = lJNIEnv->CallObjectMethod(objectWindowManager, methodGetDefaultDisplay); + + jclass classDisplay = lJNIEnv->FindClass("android/view/Display"); + jmethodID methodGetMetrics; + + // getRealMetrics is only supported on API level 17 and above, if we are below that, we will fall back to getMetrics + if(sf::priv::getAndroidApiLevel(activity) >= 17) + methodGetMetrics = lJNIEnv->GetMethodID(classDisplay, "getRealMetrics", "(Landroid/util/DisplayMetrics;)V"); + else + methodGetMetrics = lJNIEnv->GetMethodID(classDisplay, "getMetrics", "(Landroid/util/DisplayMetrics;)V"); + lJNIEnv->CallVoidMethod(objectDisplay, methodGetMetrics, objectDisplayMetrics); + + jfieldID fieldWidthPixels = lJNIEnv->GetFieldID(classDisplayMetrics, "widthPixels", "I"); + jfieldID fieldHeightPixels = lJNIEnv->GetFieldID(classDisplayMetrics, "heightPixels", "I"); + + *width = lJNIEnv->GetIntField(objectDisplayMetrics, fieldWidthPixels); + *height = lJNIEnv->GetIntField(objectDisplayMetrics, fieldHeightPixels); +} + + //////////////////////////////////////////////////////////// static void onStart(ANativeActivity* activity) { @@ -563,6 +605,7 @@ JNIEXPORT void ANativeActivity_onCreate(ANativeActivity* activity, void* savedSt eglInitialize(states->display, NULL, NULL); getScreenSizeInPixels(activity, &states->screenSize.x, &states->screenSize.y); + getFullScreenSizeInPixels(activity, &states->fullScreenSize.x, &states->fullScreenSize.y); // Redirect error messages to logcat sf::err().rdbuf(&states->logcat); diff --git a/src/SFML/System/Android/Activity.hpp b/src/SFML/System/Android/Activity.hpp index 0adcf1a21..911244ec5 100644 --- a/src/SFML/System/Android/Activity.hpp +++ b/src/SFML/System/Android/Activity.hpp @@ -80,6 +80,7 @@ struct ActivityStates bool mainOver; Vector2i screenSize; + Vector2i fullScreenSize; bool initialized; bool terminated; diff --git a/src/SFML/Window/Android/VideoModeImpl.cpp b/src/SFML/Window/Android/VideoModeImpl.cpp index 71535a4a3..0938c4eb3 100644 --- a/src/SFML/Window/Android/VideoModeImpl.cpp +++ b/src/SFML/Window/Android/VideoModeImpl.cpp @@ -38,7 +38,15 @@ namespace priv //////////////////////////////////////////////////////////// std::vector VideoModeImpl::getFullscreenModes() { - VideoMode desktop = getDesktopMode(); + // Get the activity states + priv::ActivityStates& states = priv::getActivity(); + + VideoMode desktop; + + { + Lock lock(states.mutex); + desktop = VideoMode(static_cast(states.fullScreenSize.x), static_cast(states.fullScreenSize.y)); + } // Return both portrait and landscape resolutions std::vector modes; From 39cf24ba3693b7f1267deef065b075844100b934 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lukas=20D=C3=BCrrenberger?= Date: Sat, 9 Nov 2024 18:47:10 +0100 Subject: [PATCH 3/4] Update changelog for 2.6.2 --- changelog.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/changelog.md b/changelog.md index 0e59b0e23..8ed68261f 100644 --- a/changelog.md +++ b/changelog.md @@ -1,6 +1,6 @@ # Changelog -## Unreleased SFML 2.6.2 +## SFML 2.6.2 ### General @@ -23,6 +23,8 @@ - [Android] Remove use of deprecated `ALooper_pollAll` (#3181, #3189) - [macOS] Fix how macOS fullscreen video modes are detected (#2300, #3151) - [macOS] Prevent unnecessary macOS input monitoring permission prompts (#2843, #3235) +- [Linux] Fix DRM mode setting to use SFML window dimensions (#3136) +- [Android] Fix wrong fullscreen resolution (#1349, #1559, #2396) ### Graphics From 5383d2b3948f805af55c9f8a4587ac72ec5981d1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lukas=20D=C3=BCrrenberger?= Date: Sat, 9 Nov 2024 18:49:19 +0100 Subject: [PATCH 4/4] Update SFML version to 2.6.2 --- CMakeLists.txt | 2 +- examples/assets/info.plist | 2 +- include/SFML/Config.hpp | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index cbc9c8fae..a302f233f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -41,7 +41,7 @@ include(GNUInstallDirs) # setup version numbers set(VERSION_MAJOR 2) set(VERSION_MINOR 6) -set(VERSION_PATCH 1) +set(VERSION_PATCH 2) # add an option for choosing the build type (shared or static) if(NOT SFML_OS_ANDROID) diff --git a/examples/assets/info.plist b/examples/assets/info.plist index 655be45e2..bb14f43dd 100644 --- a/examples/assets/info.plist +++ b/examples/assets/info.plist @@ -17,7 +17,7 @@ CFBundleInfoDictionaryVersion 6.0 CFBundleLongVersionString - 2.6.1 + 2.6.2 CFBundleName $(EXECUTABLE_NAME) CFBundlePackageType diff --git a/include/SFML/Config.hpp b/include/SFML/Config.hpp index 3093a7a51..ad4e1d8f8 100644 --- a/include/SFML/Config.hpp +++ b/include/SFML/Config.hpp @@ -31,7 +31,7 @@ //////////////////////////////////////////////////////////// #define SFML_VERSION_MAJOR 2 #define SFML_VERSION_MINOR 6 -#define SFML_VERSION_PATCH 1 +#define SFML_VERSION_PATCH 2 ////////////////////////////////////////////////////////////