aboutsummaryrefslogtreecommitdiff
path: root/source/Irrlicht/CEGLManager.cpp
diff options
context:
space:
mode:
authorcutealien <cutealien@dfc29bdd-3216-0410-991c-e03cc46cb475>2020-01-03 19:05:16 +0000
committercutealien <cutealien@dfc29bdd-3216-0410-991c-e03cc46cb475>2020-01-03 19:05:16 +0000
commit2ae2a551a6290f46734307bbfdafea4b1a2cf2ba (patch)
treeba2f0b468640e44899fed3df2d4cc58795f4a003 /source/Irrlicht/CEGLManager.cpp
downloadirrlicht-2ae2a551a6290f46734307bbfdafea4b1a2cf2ba.tar.xz
Merging r5975 through r6036 from trunk to ogl-es branch.
GLES drivers adapted, but only did make compile-tests. git-svn-id: svn://svn.code.sf.net/p/irrlicht/code/branches/ogl-es@6038 dfc29bdd-3216-0410-991c-e03cc46cb475
Diffstat (limited to 'source/Irrlicht/CEGLManager.cpp')
-rwxr-xr-xsource/Irrlicht/CEGLManager.cpp662
1 files changed, 662 insertions, 0 deletions
diff --git a/source/Irrlicht/CEGLManager.cpp b/source/Irrlicht/CEGLManager.cpp
new file mode 100755
index 0000000..49b7290
--- /dev/null
+++ b/source/Irrlicht/CEGLManager.cpp
@@ -0,0 +1,662 @@
+// Copyright (C) 2013 Patryk Nadrowski
+// This file is part of the "Irrlicht Engine".
+// For conditions of distribution and use, see copyright notice in Irrlicht.h
+
+#include "CEGLManager.h"
+
+#ifdef _IRR_COMPILE_WITH_EGL_MANAGER_
+
+#include "irrString.h"
+#include "irrArray.h"
+#include "os.h"
+
+#if defined(_IRR_COMPILE_WITH_ANDROID_DEVICE_)
+#include <android/native_activity.h>
+#endif
+
+namespace irr
+{
+namespace video
+{
+
+CEGLManager::CEGLManager() : IContextManager(), EglWindow(0), EglDisplay(EGL_NO_DISPLAY),
+ EglSurface(EGL_NO_SURFACE), EglContext(EGL_NO_CONTEXT), EglConfig(0), MajorVersion(0), MinorVersion(0)
+{
+ #ifdef _DEBUG
+ setDebugName("CEGLManager");
+ #endif
+}
+
+CEGLManager::~CEGLManager()
+{
+ destroyContext();
+ destroySurface();
+ terminate();
+}
+
+bool CEGLManager::initialize(const SIrrlichtCreationParameters& params, const SExposedVideoData& data)
+{
+ // store new data
+ Params=params;
+ Data=data;
+
+ if (EglWindow != 0 && EglDisplay != EGL_NO_DISPLAY)
+ 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_)
+ 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);
+#elif defined(_IRR_COMPILE_WITH_ANDROID_DEVICE_)
+ EglWindow = (ANativeWindow*)Data.OGLESAndroid.Window;
+ EglDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY);
+#elif defined(_IRR_COMPILE_WITH_FB_DEVICE_)
+ EglWindow = (NativeWindowType)Data.OpenGLFB.Window;
+ EglDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY);
+#endif
+
+ // We must check if EGL display is valid.
+ if (EglDisplay == EGL_NO_DISPLAY)
+ {
+ os::Printer::log("Could not get EGL display.");
+ terminate();
+ return false;
+ }
+
+ // Initialize EGL here.
+ if (!eglInitialize(EglDisplay, &MajorVersion, &MinorVersion))
+ {
+ os::Printer::log("Could not initialize EGL display.");
+
+ EglDisplay = EGL_NO_DISPLAY;
+ terminate();
+ return false;
+ }
+ else
+ os::Printer::log("EGL version", core::stringc(MajorVersion+(MinorVersion*0.1f)).c_str());
+
+ return true;
+}
+
+void CEGLManager::terminate()
+{
+ if (EglWindow == 0 && EglDisplay == EGL_NO_DISPLAY)
+ return;
+
+ if (EglDisplay != EGL_NO_DISPLAY)
+ {
+ // We should unbind current EGL context before terminate EGL.
+ eglMakeCurrent(EglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
+
+ eglTerminate(EglDisplay);
+ 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;
+}
+
+bool CEGLManager::generateSurface()
+{
+ if (EglDisplay == EGL_NO_DISPLAY)
+ return false;
+
+ if (EglSurface != EGL_NO_SURFACE)
+ return true;
+
+ // We should assign new WindowID on platforms, where WindowID may change at runtime,
+ // at this time only Android support this feature.
+ // this needs an update method instead!
+
+#if defined(_IRR_COMPILE_WITH_ANDROID_DEVICE_)
+ EglWindow = (ANativeWindow*)Data.OGLESAndroid.Window;
+#endif
+
+#if defined(_IRR_EMSCRIPTEN_PLATFORM_)
+ // eglChooseConfig is currently only implemented as stub in emscripten (version 1.37.22 at point of writing)
+ // But the other solution would also be fine as it also only generates a single context so there is not much to choose from.
+ EglConfig = chooseConfig(ECS_IRR_CHOOSE);
+#else
+ EglConfig = chooseConfig(ECS_EGL_CHOOSE_FIRST_LOWER_EXPECTATIONS);
+#endif
+
+ if ( EglConfig == 0 )
+ {
+ os::Printer::log("Could not get config for EGL display.");
+ return false;
+ }
+
+
+#if defined(_IRR_COMPILE_WITH_ANDROID_DEVICE_)
+ EGLint Format = 0;
+ eglGetConfigAttrib(EglDisplay, EglConfig, EGL_NATIVE_VISUAL_ID, &Format);
+
+ ANativeWindow_setBuffersGeometry(EglWindow, 0, 0, Format);
+#endif
+
+ // Now we are able to create EGL surface.
+ EglSurface = eglCreateWindowSurface(EglDisplay, EglConfig, EglWindow, 0);
+
+ if (EGL_NO_SURFACE == EglSurface)
+ EglSurface = eglCreateWindowSurface(EglDisplay, EglConfig, 0, 0);
+
+ if (EGL_NO_SURFACE == EglSurface)
+ os::Printer::log("Could not create EGL surface.");
+
+#ifdef EGL_VERSION_1_2
+ if (MinorVersion > 1)
+ eglBindAPI(EGL_OPENGL_ES_API);
+#endif
+
+ if (Params.Vsync)
+ eglSwapInterval(EglDisplay, 1);
+
+ return true;
+}
+
+EGLConfig CEGLManager::chooseConfig(EConfigStyle confStyle)
+{
+ EGLConfig configResult = 0;
+
+ // Find proper OpenGL BIT.
+ EGLint eglOpenGLBIT = 0;
+ switch (Params.DriverType)
+ {
+ case EDT_OGLES1:
+ eglOpenGLBIT = EGL_OPENGL_ES_BIT;
+ break;
+ case EDT_OGLES2:
+ case EDT_WEBGL1:
+ eglOpenGLBIT = EGL_OPENGL_ES2_BIT;
+ break;
+ default:
+ break;
+ }
+
+ if ( confStyle == ECS_EGL_CHOOSE_FIRST_LOWER_EXPECTATIONS )
+ {
+ EGLint Attribs[] =
+ {
+ EGL_RED_SIZE, 8,
+ EGL_GREEN_SIZE, 8,
+ EGL_BLUE_SIZE, 8,
+ EGL_ALPHA_SIZE, Params.WithAlphaChannel ? 1:0,
+ EGL_BUFFER_SIZE, Params.Bits,
+ EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
+ EGL_DEPTH_SIZE, Params.ZBufferBits,
+ EGL_STENCIL_SIZE, Params.Stencilbuffer,
+ EGL_SAMPLE_BUFFERS, Params.AntiAlias ? 1:0,
+ EGL_SAMPLES, Params.AntiAlias,
+ #ifdef EGL_VERSION_1_3
+ EGL_RENDERABLE_TYPE, eglOpenGLBIT,
+ #endif
+ EGL_NONE, 0
+ };
+
+ EGLint numConfigs = 0;
+ u32 steps = 5;
+
+ // Choose the best EGL config.
+ // TODO: We should also have a confStyle ECS_EGL_CHOOSE_CLOSEST
+ // which doesn't take first result of eglChooseConfigs,
+ // but the closest to requested parameters. eglChooseConfigs
+ // can return more than 1 result and first one might have
+ // "better" values than requested (more bits per pixel etc).
+ // So this returns the config which can do most, not the
+ // config which is closest to the requested parameters.
+ //
+ while (!eglChooseConfig(EglDisplay, Attribs, &configResult, 1, &numConfigs) || !numConfigs)
+ {
+ switch (steps)
+ {
+ case 5: // samples
+ if (Attribs[19] > 2) // Params.AntiAlias
+ --Attribs[19];
+ else
+ {
+ Attribs[17] = 0; // Params.Stencilbuffer
+ Attribs[19] = 0; // Params.AntiAlias
+ --steps;
+ }
+ break;
+ case 4: // alpha
+ if (Attribs[7]) // Params.WithAlphaChannel
+ {
+ Attribs[7] = 0;
+
+ if (Params.AntiAlias)
+ {
+ Attribs[17] = 1;
+ Attribs[19] = Params.AntiAlias;
+ steps = 5;
+ }
+ }
+ else
+ --steps;
+ break;
+ case 3: // stencil
+ if (Attribs[15]) // Params.Stencilbuffer
+ {
+ Attribs[15] = 0;
+
+ if (Params.AntiAlias)
+ {
+ Attribs[17] = 1;
+ Attribs[19] = Params.AntiAlias;
+ steps = 5;
+ }
+ }
+ else
+ --steps;
+ break;
+ case 2: // depth size
+ if (Attribs[13] > 16) // Params.ZBufferBits
+ {
+ Attribs[13] -= 8;
+ }
+ else
+ --steps;
+ break;
+ case 1: // buffer size
+ if (Attribs[9] > 16) // Params.Bits
+ {
+ Attribs[9] -= 8;
+ }
+ else
+ --steps;
+ break;
+ default:
+ return 0;
+ }
+ }
+
+ if (Params.AntiAlias && !Attribs[17])
+ os::Printer::log("No multisampling.");
+
+ if (Params.WithAlphaChannel && !Attribs[7])
+ os::Printer::log("No alpha.");
+
+ if (Params.Stencilbuffer && !Attribs[15])
+ os::Printer::log("No stencil buffer.");
+
+ if (Params.ZBufferBits > Attribs[13])
+ os::Printer::log("No full depth buffer.");
+
+ if (Params.Bits > Attribs[9])
+ os::Printer::log("No full color buffer.");
+ }
+ else if ( confStyle == ECS_IRR_CHOOSE )
+ {
+ // find number of available configs
+ EGLint numConfigs;
+ if ( eglGetConfigs( EglDisplay, NULL, 0, &numConfigs) == EGL_FALSE )
+ {
+ testEGLError();
+ return 0;
+ }
+
+ if ( numConfigs <= 0 )
+ return 0;
+
+ // Get all available configs.
+ EGLConfig * configs = new EGLConfig[numConfigs];
+ if ( eglGetConfigs( EglDisplay, configs, numConfigs, &numConfigs) == EGL_FALSE )
+ {
+ testEGLError();
+ return 0;
+ }
+
+ // Find the best one.
+ core::array<SConfigRating> ratings((u32)numConfigs);
+ for ( u32 i=0; i < (u32)numConfigs; ++i )
+ {
+ SConfigRating r;
+ r.config = configs[i];
+ r.rating = rateConfig(r.config, eglOpenGLBIT);
+
+ if ( r.rating >= 0 )
+ ratings.push_back(r);
+ }
+
+ if ( ratings.size() > 0 )
+ {
+ ratings.sort();
+ configResult = ratings[0].config;
+
+ if ( ratings[0].rating != 0 )
+ {
+ // This is just to print some log info (it also rates again while doing that, but rating is cheap enough, so that doesn't matter here).
+ rateConfig(ratings[0].config, eglOpenGLBIT, true);
+ }
+ }
+
+ delete[] configs;
+ }
+
+ return configResult;
+}
+
+irr::s32 CEGLManager::rateConfig(EGLConfig config, EGLint eglOpenGLBIT, bool log)
+{
+ // some values must be there or we ignore the config
+#ifdef EGL_VERSION_1_3
+ EGLint attribRenderableType = 0;
+ eglGetConfigAttrib( EglDisplay, config, EGL_RENDERABLE_TYPE, &attribRenderableType);
+ if ( attribRenderableType != eglOpenGLBIT )
+ {
+ if ( log )
+ os::Printer::log("EGL_RENDERABLE_TYPE != eglOpenGLBIT");
+ return -1;
+ }
+#endif
+ EGLint attribSurfaceType = 0;
+ eglGetConfigAttrib( EglDisplay, config, EGL_SURFACE_TYPE, &attribSurfaceType);
+ if ( attribSurfaceType != EGL_WINDOW_BIT )
+ {
+ if ( log )
+ os::Printer::log("EGL_SURFACE_TYPE!= EGL_WINDOW_BIT");
+ return -1;
+ }
+
+ // Generally we give a really bad rating if attributes are worse than requested
+ // We give a slight worse rating if attributes are not exact as requested
+ // And we use some priorities which might make sense (but not really fine-tuned,
+ // so if you think other priorities would be better don't worry about changing the values.
+ int rating = 0;
+
+ EGLint attribBufferSize = 0;
+ eglGetConfigAttrib( EglDisplay, config, EGL_BUFFER_SIZE, &attribBufferSize);
+ if ( attribBufferSize < Params.Bits )
+ {
+ if ( log )
+ os::Printer::log("No full color buffer.");
+ rating += 100;
+ }
+ if ( attribBufferSize > Params.Bits )
+ {
+ if ( log )
+ os::Printer::log("Larger color buffer.", ELL_DEBUG);
+ ++rating;
+ }
+
+ EGLint attribRedSize = 0;
+ eglGetConfigAttrib( EglDisplay, config, EGL_RED_SIZE, &attribRedSize);
+ if ( attribRedSize < 5 && Params.Bits >= 4 )
+ rating += 100;
+ else if ( attribRedSize < 8 && Params.Bits >= 24)
+ rating += 10;
+ else if ( attribRedSize >= 8 && Params.Bits < 24 )
+ rating ++;
+ EGLint attribGreenSize = 0;
+ eglGetConfigAttrib( EglDisplay, config, EGL_GREEN_SIZE, &attribGreenSize);
+ if ( attribGreenSize < 5 && Params.Bits >= 4 )
+ rating += 100;
+ else if ( attribGreenSize < 8 && Params.Bits >= 24)
+ rating += 10;
+ else if ( attribGreenSize >= 8 && Params.Bits < 24 )
+ rating ++;
+ EGLint attribBlueSize = 0;
+ eglGetConfigAttrib( EglDisplay, config, EGL_BLUE_SIZE, &attribBlueSize);
+ if ( attribBlueSize < 5 && Params.Bits >= 4 )
+ rating += 100;
+ else if ( attribBlueSize < 8 && Params.Bits >= 24)
+ rating += 10;
+ else if ( attribBlueSize >= 8 && Params.Bits < 24 )
+ rating ++;
+
+ EGLint attribAlphaSize = 0;
+ eglGetConfigAttrib( EglDisplay, config, EGL_ALPHA_SIZE, &attribAlphaSize);
+ if ( Params.WithAlphaChannel && attribAlphaSize == 0 )
+ {
+ if ( log )
+ os::Printer::log("No alpha.");
+ rating += 10;
+ }
+ else if ( !Params.WithAlphaChannel && attribAlphaSize > 0 )
+ {
+ if ( log )
+ os::Printer::log("Got alpha (unrequested).", ELL_DEBUG);
+ rating ++;
+ }
+
+ EGLint attribStencilSize = 0;
+ eglGetConfigAttrib( EglDisplay, config, EGL_STENCIL_SIZE, &attribStencilSize);
+ if ( Params.Stencilbuffer && attribStencilSize == 0 )
+ {
+ if ( log )
+ os::Printer::log("No stencil buffer.");
+ rating += 10;
+ }
+ else if ( !Params.Stencilbuffer && attribStencilSize > 0 )
+ {
+ if ( log )
+ os::Printer::log("Got a stencil buffer (unrequested).", ELL_DEBUG);
+ rating ++;
+ }
+
+ EGLint attribDepthSize = 0;
+ eglGetConfigAttrib( EglDisplay, config, EGL_DEPTH_SIZE, &attribDepthSize);
+ if ( attribDepthSize < Params.ZBufferBits )
+ {
+ if ( log )
+ {
+ if (attribDepthSize > 0)
+ os::Printer::log("No full depth buffer.");
+ else
+ os::Printer::log("No depth buffer.");
+ }
+ rating += 50;
+ }
+ else if ( attribDepthSize != Params.ZBufferBits )
+ {
+ if ( log )
+ {
+ if ( Params.ZBufferBits == 0 )
+ os::Printer::log("Got a depth buffer (unrequested).", ELL_DEBUG);
+ else
+ os::Printer::log("Got a larger depth buffer.", ELL_DEBUG);
+ }
+ rating ++;
+ }
+
+ EGLint attribSampleBuffers=0, attribSamples = 0;
+ eglGetConfigAttrib( EglDisplay, config, EGL_SAMPLE_BUFFERS, &attribSampleBuffers);
+ eglGetConfigAttrib( EglDisplay, config, EGL_SAMPLES, &attribSamples);
+ if ( Params.AntiAlias && attribSampleBuffers == 0 )
+ {
+ if ( log )
+ os::Printer::log("No multisampling.");
+ rating += 20;
+ }
+ else if ( Params.AntiAlias && attribSampleBuffers && attribSamples < Params.AntiAlias )
+ {
+ if ( log )
+ os::Printer::log("Multisampling with less samples than requested.", ELL_DEBUG);
+ rating += 10;
+ }
+ else if ( Params.AntiAlias && attribSampleBuffers && attribSamples > Params.AntiAlias )
+ {
+ if ( log )
+ os::Printer::log("Multisampling with more samples than requested.", ELL_DEBUG);
+ rating += 5;
+ }
+ else if ( !Params.AntiAlias && attribSampleBuffers > 0 )
+ {
+ if ( log )
+ os::Printer::log("Got multisampling (unrequested).", ELL_DEBUG);
+ rating += 3;
+ }
+
+ return rating;
+}
+
+void CEGLManager::destroySurface()
+{
+ if (EglSurface == EGL_NO_SURFACE)
+ return;
+
+ // We should unbind current EGL context before destroy EGL surface.
+ eglMakeCurrent(EglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
+
+ eglDestroySurface(EglDisplay, EglSurface);
+ EglSurface = EGL_NO_SURFACE;
+}
+
+bool CEGLManager::generateContext()
+{
+ if (EglDisplay == EGL_NO_DISPLAY || EglSurface == EGL_NO_SURFACE)
+ return false;
+
+ if (EglContext != EGL_NO_CONTEXT)
+ return true;
+
+ EGLint OpenGLESVersion = 0;
+
+ switch (Params.DriverType)
+ {
+ case EDT_OGLES1:
+ OpenGLESVersion = 1;
+ break;
+ case EDT_OGLES2:
+ case EDT_WEBGL1:
+ OpenGLESVersion = 2;
+ break;
+ default:
+ break;
+ }
+
+ EGLint ContextAttrib[] =
+ {
+#ifdef EGL_VERSION_1_3
+ EGL_CONTEXT_CLIENT_VERSION, OpenGLESVersion,
+#endif
+ EGL_NONE, 0
+ };
+
+ EglContext = eglCreateContext(EglDisplay, EglConfig, EGL_NO_CONTEXT, ContextAttrib);
+
+ if (testEGLError())
+ {
+ os::Printer::log("Could not create EGL context.", ELL_ERROR);
+ return false;
+ }
+
+ os::Printer::log("EGL context created with OpenGLESVersion: ", core::stringc((int)OpenGLESVersion), ELL_DEBUG);
+
+ return true;
+}
+
+void CEGLManager::destroyContext()
+{
+ if (EglContext == EGL_NO_CONTEXT)
+ return;
+
+ // We must unbind current EGL context before destroy it.
+ eglMakeCurrent(EglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
+ eglDestroyContext(EglDisplay, EglContext);
+
+ EglContext = EGL_NO_CONTEXT;
+}
+
+bool CEGLManager::activateContext(const SExposedVideoData& videoData, bool restorePrimaryOnZero)
+{
+ eglMakeCurrent(EglDisplay, EglSurface, EglSurface, EglContext);
+
+ if (testEGLError())
+ {
+ os::Printer::log("Could not make EGL context current.");
+ return false;
+ }
+ return true;
+}
+
+const SExposedVideoData& CEGLManager::getContext() const
+{
+ return Data;
+}
+
+bool CEGLManager::swapBuffers()
+{
+ return (eglSwapBuffers(EglDisplay, EglSurface)==EGL_TRUE);
+}
+
+bool CEGLManager::testEGLError()
+{
+#if defined(EGL_VERSION_1_0) && defined(_DEBUG)
+ EGLint status = eglGetError();
+
+ switch (status)
+ {
+ case EGL_SUCCESS:
+ return false;
+ case EGL_NOT_INITIALIZED :
+ os::Printer::log("Not Initialized", ELL_ERROR);
+ break;
+ case EGL_BAD_ACCESS:
+ os::Printer::log("Bad Access", ELL_ERROR);
+ break;
+ case EGL_BAD_ALLOC:
+ os::Printer::log("Bad Alloc", ELL_ERROR);
+ break;
+ case EGL_BAD_ATTRIBUTE:
+ os::Printer::log("Bad Attribute", ELL_ERROR);
+ break;
+ case EGL_BAD_CONTEXT:
+ os::Printer::log("Bad Context", ELL_ERROR);
+ break;
+ case EGL_BAD_CONFIG:
+ os::Printer::log("Bad Config", ELL_ERROR);
+ break;
+ case EGL_BAD_CURRENT_SURFACE:
+ os::Printer::log("Bad Current Surface", ELL_ERROR);
+ break;
+ case EGL_BAD_DISPLAY:
+ os::Printer::log("Bad Display", ELL_ERROR);
+ break;
+ case EGL_BAD_SURFACE:
+ os::Printer::log("Bad Surface", ELL_ERROR);
+ break;
+ case EGL_BAD_MATCH:
+ os::Printer::log("Bad Match", ELL_ERROR);
+ break;
+ case EGL_BAD_PARAMETER:
+ os::Printer::log("Bad Parameter", ELL_ERROR);
+ break;
+ case EGL_BAD_NATIVE_PIXMAP:
+ os::Printer::log("Bad Native Pixmap", ELL_ERROR);
+ break;
+ case EGL_BAD_NATIVE_WINDOW:
+ os::Printer::log("Bad Native Window", ELL_ERROR);
+ break;
+ case EGL_CONTEXT_LOST:
+ os::Printer::log("Context Lost", ELL_ERROR);
+ break;
+ default:
+ break;
+ };
+
+ return true;
+#else
+ return false;
+#endif
+}
+
+}
+}
+
+#endif