Browse Source

Merge branch 'backends'

Michael Ragazzon 3 years ago
parent
commit
987c7d0dcf
100 changed files with 11161 additions and 4454 deletions
  1. 2 2
      .appveyor.yml
  2. 3 0
      .clang-format
  3. 48 13
      .github/workflows/build.yml
  4. 72 0
      Backends/RmlUi_Backend.h
  5. 246 0
      Backends/RmlUi_Backend_GLFW_GL2.cpp
  6. 258 0
      Backends/RmlUi_Backend_GLFW_GL3.cpp
  7. 340 0
      Backends/RmlUi_Backend_SDL_GL2.cpp
  8. 314 0
      Backends/RmlUi_Backend_SDL_GL3.cpp
  9. 200 0
      Backends/RmlUi_Backend_SDL_SDLrenderer.cpp
  10. 278 0
      Backends/RmlUi_Backend_SFML_GL2.cpp
  11. 448 0
      Backends/RmlUi_Backend_Win32_GL2.cpp
  12. 294 0
      Backends/RmlUi_Backend_X11_GL2.cpp
  13. 3582 0
      Backends/RmlUi_Include_GL3.h
  14. 18 18
      Backends/RmlUi_Include_Windows.h
  15. 18 12
      Backends/RmlUi_Include_Xlib.h
  16. 323 0
      Backends/RmlUi_Platform_GLFW.cpp
  17. 86 0
      Backends/RmlUi_Platform_GLFW.h
  18. 296 0
      Backends/RmlUi_Platform_SDL.cpp
  19. 43 19
      Backends/RmlUi_Platform_SDL.h
  20. 244 0
      Backends/RmlUi_Platform_SFML.cpp
  21. 88 0
      Backends/RmlUi_Platform_SFML.h
  22. 482 0
      Backends/RmlUi_Platform_Win32.cpp
  23. 90 0
      Backends/RmlUi_Platform_Win32.h
  24. 638 0
      Backends/RmlUi_Platform_X11.cpp
  25. 106 0
      Backends/RmlUi_Platform_X11.h
  26. 274 0
      Backends/RmlUi_Renderer_GL2.cpp
  27. 70 68
      Backends/RmlUi_Renderer_GL2.h
  28. 700 0
      Backends/RmlUi_Renderer_GL3.cpp
  29. 58 39
      Backends/RmlUi_Renderer_GL3.h
  30. 155 0
      Backends/RmlUi_Renderer_SDL.cpp
  31. 61 66
      Backends/RmlUi_Renderer_SDL.h
  32. 87 0
      CMake/BackendFileList.cmake
  33. 0 36
      CMake/Modules/FindCarbon.cmake
  34. 10 0
      CMake/Modules/FindSDL2.cmake
  35. 4 73
      CMake/SampleFileList.cmake
  36. 1 36
      CMake/gen_samplelists.sh
  37. 200 145
      CMakeLists.txt
  38. 3 1
      Include/RmlUi/Core/Debug.h
  39. 2 2
      Include/RmlUi/Core/Input.h
  40. 4 0
      Include/RmlUi/Core/Platform.h
  41. 0 1
      Include/RmlUi/Core/TypeConverter.h
  42. 120 104
      Include/RmlUi/Core/TypeConverter.inl
  43. 9 6
      Samples/assets/invader.rcss
  44. 74 109
      Samples/basic/animation/src/main.cpp
  45. 74 98
      Samples/basic/benchmark/src/main.cpp
  46. 37 55
      Samples/basic/bitmapfont/src/main.cpp
  47. 10 6
      Samples/basic/customlog/src/SystemInterface.cpp
  48. 36 54
      Samples/basic/customlog/src/main.cpp
  49. 44 74
      Samples/basic/databinding/src/main.cpp
  50. 35 57
      Samples/basic/demo/src/main.cpp
  51. 34 62
      Samples/basic/drag/src/main.cpp
  52. 41 55
      Samples/basic/loaddocument/src/main.cpp
  53. 30 48
      Samples/basic/lottie/src/main.cpp
  54. 0 194
      Samples/basic/sdl2/src/RenderInterfaceSDL2.cpp
  55. 0 442
      Samples/basic/sdl2/src/SystemInterfaceSDL2.cpp
  56. 0 46
      Samples/basic/sdl2/src/SystemInterfaceSDL2.h
  57. 0 194
      Samples/basic/sdl2/src/main.cpp
  58. 0 171
      Samples/basic/sdl2_sdlrenderer/src/RenderInterfaceSDL2.cpp
  59. 0 442
      Samples/basic/sdl2_sdlrenderer/src/SystemInterfaceSDL2.cpp
  60. 0 46
      Samples/basic/sdl2_sdlrenderer/src/SystemInterfaceSDL2.h
  61. 0 175
      Samples/basic/sdl2_sdlrenderer/src/main.cpp
  62. 0 308
      Samples/basic/sfml2/src/RenderInterfaceSFML.cpp
  63. 0 346
      Samples/basic/sfml2/src/SystemInterfaceSFML.cpp
  64. 0 47
      Samples/basic/sfml2/src/SystemInterfaceSFML.h
  65. 0 231
      Samples/basic/sfml2/src/main.cpp
  66. 29 47
      Samples/basic/svg/src/main.cpp
  67. 56 81
      Samples/basic/transform/src/main.cpp
  68. 3 2
      Samples/basic/treeview/src/FileBrowser.cpp
  69. 35 56
      Samples/basic/treeview/src/main.cpp
  70. 2 2
      Samples/invaders/data/game.rml
  71. 17 26
      Samples/invaders/src/DecoratorDefender.cpp
  72. 33 21
      Samples/invaders/src/DecoratorStarfield.cpp
  73. 1 1
      Samples/invaders/src/DecoratorStarfield.h
  74. 11 14
      Samples/invaders/src/Defender.cpp
  75. 3 3
      Samples/invaders/src/Defender.h
  76. 7 5
      Samples/invaders/src/ElementGame.cpp
  77. 4 3
      Samples/invaders/src/EventManager.cpp
  78. 8 20
      Samples/invaders/src/Game.cpp
  79. 2 2
      Samples/invaders/src/Game.h
  80. 14 21
      Samples/invaders/src/Invader.cpp
  81. 3 3
      Samples/invaders/src/Invader.h
  82. 4 4
      Samples/invaders/src/Mothership.cpp
  83. 1 1
      Samples/invaders/src/Mothership.h
  84. 5 10
      Samples/invaders/src/Shield.cpp
  85. 49 18
      Samples/invaders/src/Sprite.cpp
  86. 10 3
      Samples/invaders/src/Sprite.h
  87. 37 57
      Samples/invaders/src/main.cpp
  88. 2 2
      Samples/luainvaders/data/background.rml
  89. 3 3
      Samples/luainvaders/data/game.rml
  90. 17 26
      Samples/luainvaders/src/DecoratorDefender.cpp
  91. 36 24
      Samples/luainvaders/src/DecoratorStarfield.cpp
  92. 1 1
      Samples/luainvaders/src/DecoratorStarfield.h
  93. 18 21
      Samples/luainvaders/src/Defender.cpp
  94. 3 3
      Samples/luainvaders/src/Defender.h
  95. 7 5
      Samples/luainvaders/src/ElementGame.cpp
  96. 8 20
      Samples/luainvaders/src/Game.cpp
  97. 3 3
      Samples/luainvaders/src/Game.h
  98. 25 32
      Samples/luainvaders/src/Invader.cpp
  99. 6 6
      Samples/luainvaders/src/Invader.h
  100. 8 7
      Samples/luainvaders/src/LuaInterface.cpp

+ 2 - 2
.appveyor.yml

@@ -36,7 +36,7 @@ install:
     cmake --build . --target rlottie --config Release -- "/clp:ErrorsOnly"
     cd ../../
     
-    git clone --depth 1 --branch v2.3.0 https://github.com/sammycage/lunasvg.git
+    git clone --depth 1 --branch v2.3.1 https://github.com/sammycage/lunasvg.git
     cd lunasvg
     mkdir build
     cd build
@@ -105,7 +105,7 @@ after_build:
     cp Include/RmlUi/Core/Containers/LICENSE.txt LICENSE.Core.ThirdParty.txt
     cp Source/Debugger/LICENSE.txt LICENSE.Debugger.ThirdParty.txt
     
-    7z a RmlUi-%VS_SHORTNAME%-%PLATFORM_NAME%.zip Bin/ Include/ Samples/ Build.txt readme.md changelog.md LICENSE* Dependencies/freetype-%FREETYPE_VER%/ Dependencies/rlottie/COPYING Dependencies/rlottie/MPL_SOURCE.txt Dependencies/rlottie/licenses/ Dependencies/lunasvg/LICENSE
+    7z a RmlUi-%VS_SHORTNAME%-%PLATFORM_NAME%.zip Backends/ Bin/ Include/ Samples/ Build.txt readme.md changelog.md LICENSE* Dependencies/freetype-%FREETYPE_VER%/ Dependencies/rlottie/COPYING Dependencies/rlottie/MPL_SOURCE.txt Dependencies/rlottie/licenses/ Dependencies/lunasvg/LICENSE
     
     mkdir Samples\Dependencies\freetype-%FREETYPE_VER%, Samples\Dependencies\rlottie, Samples\Dependencies\rlottie\licenses, Samples\Dependencies\lunasvg
     cp LICENSE* Samples

+ 3 - 0
.clang-format

@@ -28,6 +28,9 @@ CompactNamespaces: false
 Cpp11BracedListStyle: true
 FixNamespaceComments: true
 IncludeBlocks: Merge
+IncludeCategories:
+  - Regex:           '^<RmlUi/'
+    Priority:        1
 IndentCaseLabels: false
 IndentPPDirectives: BeforeHash
 IndentWidth: 4

+ 48 - 13
.github/workflows/build.yml

@@ -17,12 +17,12 @@ jobs:
         include:
           - cc: clang
             cxx: clang++
-            cmake_options: -DENABLE_PRECOMPILED_HEADERS=OFF
+            cmake_options: -DENABLE_PRECOMPILED_HEADERS=OFF -DSAMPLES_BACKEND=GLFW_GL2
           - cmake_options: -DBUILD_TESTING=ON -DENABLE_PRECOMPILED_HEADERS=OFF
             enable_testing: true
-          - cmake_options: -DNO_FONT_INTERFACE_DEFAULT=ON -DENABLE_LOTTIE_PLUGIN=ON
-          - cmake_options: -DDISABLE_RTTI_AND_EXCEPTIONS=ON
-          - cmake_options: -DNO_THIRDPARTY_CONTAINERS=ON
+          - cmake_options: -DNO_FONT_INTERFACE_DEFAULT=ON -DENABLE_LOTTIE_PLUGIN=ON -DSAMPLES_BACKEND=X11_GL2
+          - cmake_options: -DDISABLE_RTTI_AND_EXCEPTIONS=ON -DSAMPLES_BACKEND=SDL_GL2
+          - cmake_options: -DNO_THIRDPARTY_CONTAINERS=ON -DSAMPLES_BACKEND=SFML_GL2
 
     steps:
     - uses: actions/checkout@v2
@@ -30,13 +30,12 @@ jobs:
     - name: Install Dependencies
       run: |-
         sudo apt-get update
-        sudo apt-get install cmake ninja-build libsdl2-dev libsdl2-image-dev libfreetype6-dev libglew-dev liblua5.2-dev libsfml-dev librlottie-dev
+        sudo apt-get install cmake ninja-build libsdl2-dev libsdl2-image-dev libfreetype6-dev libglew-dev liblua5.2-dev libsfml-dev librlottie-dev libglfw3-dev
       
     - name: Create Build Environment
       run: cmake -E make_directory ${{github.workspace}}/Build
 
     - name: Configure CMake
-      shell: bash
       working-directory: ${{github.workspace}}/Build
       run: >-
         cmake $GITHUB_WORKSPACE -G Ninja -DCMAKE_BUILD_TYPE=$BUILD_TYPE -DBUILD_LUA_BINDINGS=ON -DBUILD_SAMPLES=ON -DWARNINGS_AS_ERRORS=ON
@@ -44,13 +43,11 @@ jobs:
 
     - name: Build
       working-directory: ${{github.workspace}}/Build
-      shell: bash
       run: cmake --build . --config $BUILD_TYPE
 
     - name: Test
       if: ${{ matrix.enable_testing }}
       working-directory: ${{github.workspace}}/Build
-      shell: bash
       run: ctest -C $BUILD_TYPE
 
 
@@ -59,22 +56,60 @@ jobs:
     
     env:
       BUILD_TYPE: Release
-
+    
+    strategy:
+      fail-fast: false
+      matrix:
+        include:
+          - cmake_options: -DSAMPLES_BACKEND=auto
+          - cmake_options: -DSAMPLES_BACKEND=GLFW_GL2
+    
     steps:
     - uses: actions/checkout@v2
       
     - name: Install Dependencies
-      run: brew install lua
+      run: brew install lua sdl2 sdl2_image glfw
       
     - name: Create Build Environment
       run: cmake -E make_directory ${{github.workspace}}/Build
 
     - name: Configure CMake
-      shell: bash
       working-directory: ${{github.workspace}}/Build
-      run: cmake $GITHUB_WORKSPACE -DCMAKE_BUILD_TYPE=$BUILD_TYPE -DBUILD_LUA_BINDINGS=ON -DBUILD_SAMPLES=OFF -DWARNINGS_AS_ERRORS=ON
+      run: >-
+        cmake $GITHUB_WORKSPACE -DCMAKE_BUILD_TYPE=$BUILD_TYPE -DBUILD_LUA_BINDINGS=ON -DBUILD_SAMPLES=ON -DWARNINGS_AS_ERRORS=ON
+        ${{ matrix.cmake_options }}
 
     - name: Build
       working-directory: ${{github.workspace}}/Build
-      shell: bash
       run: cmake --build . --config $BUILD_TYPE
+
+
+  Emscripten:
+    runs-on: ubuntu-20.04
+    steps:
+    - uses: actions/checkout@v2
+
+    - name: Install Dependencies
+      run: |-
+        sudo apt-get update
+        sudo apt-get install cmake
+        wget -q https://github.com/emscripten-core/emsdk/archive/master.tar.gz
+        tar -xvf master.tar.gz
+        emsdk-master/emsdk update
+        emsdk-master/emsdk install latest
+        emsdk-master/emsdk activate latest
+              
+    - name: Create Build Environment
+      run: cmake -E make_directory Build
+      
+    - name: Configure CMake
+      run: |-
+        source emsdk-master/emsdk_env.sh
+        cd Build
+        emcmake cmake $GITHUB_WORKSPACE -DBUILD_SAMPLES=ON -DBUILD_SHARED_LIBS=OFF -DWARNINGS_AS_ERRORS=ON
+
+    - name: Build
+      run: |-
+        source emsdk-master/emsdk_env.sh
+        cd Build
+        emmake make -j4

+ 72 - 0
Backends/RmlUi_Backend.h

@@ -0,0 +1,72 @@
+/*
+ * This source file is part of RmlUi, the HTML/CSS Interface Middleware
+ *
+ * For the latest information, see http://github.com/mikke89/RmlUi
+ *
+ * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd
+ * Copyright (c) 2019 The RmlUi Team, and contributors
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ */
+
+#ifndef RMLUI_BACKENDS_BACKEND_H
+#define RMLUI_BACKENDS_BACKEND_H
+
+#include <RmlUi/Core/Input.h>
+#include <RmlUi/Core/RenderInterface.h>
+#include <RmlUi/Core/SystemInterface.h>
+#include <RmlUi/Core/Types.h>
+
+using KeyDownCallback = bool (*)(Rml::Context* context, Rml::Input::KeyIdentifier key, int key_modifier, float native_dp_ratio, bool priority);
+
+/**
+    This interface serves as a basic abstraction over the various backends included with RmlUi. It is mainly intended as an example to get something
+    simple up and running, and provides just enough functionality for the included samples.
+
+    This interface may be used directly for simple applications and testing. However, for anything more advanced we recommend to use the backend as a
+    starting point and copy relevant parts into the main loop of your application. On the other hand, the underlying platform and renderer used by the
+    backend are intended to be re-usable as is.
+ */
+namespace Backend {
+
+// Initializes the backend, including the custom system and render interfaces, and opens a window for rendering the RmlUi context.
+bool Initialize(const char* window_name, int width, int height, bool allow_resize);
+// Closes the window and release all resources owned by the backend, including the system and render interfaces.
+void Shutdown();
+
+// Returns a pointer to the custom system interface which should be provided to RmlUi.
+Rml::SystemInterface* GetSystemInterface();
+// Returns a pointer to the custom render interface which should be provided to RmlUi.
+Rml::RenderInterface* GetRenderInterface();
+
+// Polls and processes events from the current platform, and applies any relevant events to the provided RmlUi context and the key down callback.
+// @return False to indicate that the application should be closed.
+bool ProcessEvents(Rml::Context* context, KeyDownCallback key_down_callback = nullptr);
+// Request application closure during the next event processing call.
+void RequestExit();
+
+// Prepares the render state to accept rendering commands from RmlUi, call before rendering the RmlUi context.
+void BeginFrame();
+// Presents the rendered frame to the screen, call after rendering the RmlUi context.
+void PresentFrame();
+
+} // namespace Backend
+
+#endif

+ 246 - 0
Backends/RmlUi_Backend_GLFW_GL2.cpp

@@ -0,0 +1,246 @@
+/*
+ * This source file is part of RmlUi, the HTML/CSS Interface Middleware
+ *
+ * For the latest information, see http://github.com/mikke89/RmlUi
+ *
+ * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd
+ * Copyright (c) 2019 The RmlUi Team, and contributors
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ */
+
+#include "RmlUi_Backend.h"
+#include "RmlUi_Platform_GLFW.h"
+#include "RmlUi_Renderer_GL2.h"
+#include <RmlUi/Core/Context.h>
+#include <RmlUi/Core/Input.h>
+#include <RmlUi/Core/Profiling.h>
+#include <GLFW/glfw3.h>
+
+static void SetupCallbacks(GLFWwindow* window);
+
+static void LogErrorFromGLFW(int error, const char* description)
+{
+	Rml::Log::Message(Rml::Log::LT_ERROR, "GLFW error (0x%x): %s", error, description);
+}
+
+/**
+    Global data used by this backend.
+
+    Lifetime governed by the calls to Backend::Initialize() and Backend::Shutdown().
+ */
+struct BackendData {
+	SystemInterface_GLFW system_interface;
+	RenderInterface_GL2 render_interface;
+	GLFWwindow* window = nullptr;
+	int glfw_active_modifiers = 0;
+	bool context_dimensions_dirty = true;
+
+	// Arguments set during event processing and nulled otherwise.
+	Rml::Context* context = nullptr;
+	KeyDownCallback key_down_callback = nullptr;
+};
+static Rml::UniquePtr<BackendData> data;
+
+bool Backend::Initialize(const char* name, int width, int height, bool allow_resize)
+{
+	RMLUI_ASSERT(!data);
+
+	glfwSetErrorCallback(LogErrorFromGLFW);
+
+	if (!glfwInit())
+		return false;
+
+	// Set window hints for OpenGL 2 context creation.
+	glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 2);
+	glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 0);
+	glfwWindowHint(GLFW_DOUBLEBUFFER, GLFW_TRUE);
+
+	// Request stencil buffer of at least 8-bit size to supporting clipping on transformed elements.
+	glfwWindowHint(GLFW_STENCIL_BITS, 8);
+
+	// Enable MSAA for better-looking visuals, especially when transforms are applied.
+	glfwWindowHint(GLFW_SAMPLES, 2);
+
+	// Apply window properties and create it.
+	glfwWindowHint(GLFW_RESIZABLE, allow_resize ? GLFW_TRUE : GLFW_FALSE);
+	glfwWindowHint(GLFW_SCALE_TO_MONITOR, GLFW_TRUE);
+
+	GLFWwindow* window = glfwCreateWindow(width, height, name, nullptr, nullptr);
+	if (!window)
+		return false;
+
+	glfwMakeContextCurrent(window);
+	glfwSwapInterval(1);
+
+	data = Rml::MakeUnique<BackendData>();
+	data->window = window;
+	data->system_interface.SetWindow(window);
+
+	// The window size may have been scaled by DPI settings, get the actual pixel size.
+	glfwGetFramebufferSize(window, &width, &height);
+	data->render_interface.SetViewport(width, height);
+
+	// Setup the input and window event callback functions.
+	SetupCallbacks(window);
+
+	return true;
+}
+
+void Backend::Shutdown()
+{
+	RMLUI_ASSERT(data);
+	glfwDestroyWindow(data->window);
+	data.reset();
+	glfwTerminate();
+}
+
+Rml::SystemInterface* Backend::GetSystemInterface()
+{
+	RMLUI_ASSERT(data);
+	return &data->system_interface;
+}
+
+Rml::RenderInterface* Backend::GetRenderInterface()
+{
+	RMLUI_ASSERT(data);
+	return &data->render_interface;
+}
+
+bool Backend::ProcessEvents(Rml::Context* context, KeyDownCallback key_down_callback)
+{
+	RMLUI_ASSERT(data && context);
+
+	// The initial window size may have been affected by system DPI settings, apply the actual pixel size and dp-ratio to the context.
+	if (data->context_dimensions_dirty)
+	{
+		data->context_dimensions_dirty = false;
+
+		Rml::Vector2i window_size;
+		float dp_ratio = 1.f;
+		glfwGetFramebufferSize(data->window, &window_size.x, &window_size.y);
+		glfwGetWindowContentScale(data->window, &dp_ratio, nullptr);
+
+		context->SetDimensions(window_size);
+		context->SetDensityIndependentPixelRatio(dp_ratio);
+	}
+
+	data->context = context;
+	data->key_down_callback = key_down_callback;
+
+	glfwPollEvents();
+
+	data->context = nullptr;
+	data->key_down_callback = nullptr;
+
+	return !glfwWindowShouldClose(data->window);
+}
+
+void Backend::RequestExit()
+{
+	RMLUI_ASSERT(data);
+	glfwSetWindowShouldClose(data->window, GLFW_TRUE);
+}
+
+void Backend::BeginFrame()
+{
+	RMLUI_ASSERT(data);
+	data->render_interface.BeginFrame();
+	data->render_interface.Clear();
+}
+
+void Backend::PresentFrame()
+{
+	RMLUI_ASSERT(data);
+	data->render_interface.EndFrame();
+	glfwSwapBuffers(data->window);
+
+	// Optional, used to mark frames during performance profiling.
+	RMLUI_FrameMark;
+}
+
+static void SetupCallbacks(GLFWwindow* window)
+{
+	RMLUI_ASSERT(data);
+
+	// Key input
+	glfwSetKeyCallback(window, [](GLFWwindow* /*window*/, int glfw_key, int /*scancode*/, int glfw_action, int glfw_mods) {
+		if (!data->context)
+			return;
+
+		// Store the active modifiers for later because GLFW doesn't provide them in the callbacks to the mouse input events.
+		data->glfw_active_modifiers = glfw_mods;
+
+		// Override the default key event callback to add global shortcuts for the samples.
+		Rml::Context* context = data->context;
+		KeyDownCallback key_down_callback = data->key_down_callback;
+
+		switch (glfw_action)
+		{
+		case GLFW_PRESS:
+		case GLFW_REPEAT:
+		{
+			const Rml::Input::KeyIdentifier key = RmlGLFW::ConvertKey(glfw_key);
+			const int key_modifier = RmlGLFW::ConvertKeyModifiers(glfw_mods);
+			float dp_ratio = 1.f;
+			glfwGetWindowContentScale(data->window, &dp_ratio, nullptr);
+
+			// See if we have any global shortcuts that take priority over the context.
+			if (key_down_callback && !key_down_callback(context, key, key_modifier, dp_ratio, true))
+				break;
+			// Otherwise, hand the event over to the context by calling the input handler as normal.
+			if (!RmlGLFW::ProcessKeyCallback(context, glfw_key, glfw_action, glfw_mods))
+				break;
+			// The key was not consumed by the context either, try keyboard shortcuts of lower priority.
+			if (key_down_callback && !key_down_callback(context, key, key_modifier, dp_ratio, false))
+				break;
+		}
+		break;
+		case GLFW_RELEASE:
+			RmlGLFW::ProcessKeyCallback(context, glfw_key, glfw_action, glfw_mods);
+			break;
+		}
+	});
+
+	glfwSetCharCallback(window, [](GLFWwindow* /*window*/, unsigned int codepoint) { RmlGLFW::ProcessCharCallback(data->context, codepoint); });
+
+	// Mouse input
+	glfwSetCursorPosCallback(window, [](GLFWwindow* /*window*/, double xpos, double ypos) {
+		RmlGLFW::ProcessCursorPosCallback(data->context, xpos, ypos, data->glfw_active_modifiers);
+	});
+
+	glfwSetMouseButtonCallback(window, [](GLFWwindow* /*window*/, int button, int action, int mods) {
+		data->glfw_active_modifiers = mods;
+		RmlGLFW::ProcessMouseButtonCallback(data->context, button, action, mods);
+	});
+
+	glfwSetScrollCallback(window, [](GLFWwindow* /*window*/, double /*xoffset*/, double yoffset) {
+		RmlGLFW::ProcessScrollCallback(data->context, yoffset, data->glfw_active_modifiers);
+	});
+
+	// Window events
+	glfwSetFramebufferSizeCallback(window, [](GLFWwindow* /*window*/, int width, int height) {
+		data->render_interface.SetViewport(width, height);
+		RmlGLFW::ProcessFramebufferSizeCallback(data->context, width, height);
+	});
+
+	glfwSetWindowContentScaleCallback(window,
+		[](GLFWwindow* /*window*/, float xscale, float /*yscale*/) { RmlGLFW::ProcessContentScaleCallback(data->context, xscale); });
+}

+ 258 - 0
Backends/RmlUi_Backend_GLFW_GL3.cpp

@@ -0,0 +1,258 @@
+/*
+ * This source file is part of RmlUi, the HTML/CSS Interface Middleware
+ *
+ * For the latest information, see http://github.com/mikke89/RmlUi
+ *
+ * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd
+ * Copyright (c) 2019 The RmlUi Team, and contributors
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ */
+
+#include "RmlUi_Backend.h"
+#include "RmlUi_Platform_GLFW.h"
+#include "RmlUi_Renderer_GL3.h"
+#include <RmlUi/Core/Context.h>
+#include <RmlUi/Core/Input.h>
+#include <RmlUi/Core/Profiling.h>
+#include <GLFW/glfw3.h>
+
+static void SetupCallbacks(GLFWwindow* window);
+
+static void LogErrorFromGLFW(int error, const char* description)
+{
+	Rml::Log::Message(Rml::Log::LT_ERROR, "GLFW error (0x%x): %s", error, description);
+}
+
+/**
+    Global data used by this backend.
+
+    Lifetime governed by the calls to Backend::Initialize() and Backend::Shutdown().
+ */
+struct BackendData {
+	SystemInterface_GLFW system_interface;
+	RenderInterface_GL3 render_interface;
+	GLFWwindow* window = nullptr;
+	int glfw_active_modifiers = 0;
+	bool context_dimensions_dirty = true;
+
+	// Arguments set during event processing and nulled otherwise.
+	Rml::Context* context = nullptr;
+	KeyDownCallback key_down_callback = nullptr;
+};
+static Rml::UniquePtr<BackendData> data;
+
+bool Backend::Initialize(const char* name, int width, int height, bool allow_resize)
+{
+	RMLUI_ASSERT(!data);
+
+	glfwSetErrorCallback(LogErrorFromGLFW);
+
+	if (!glfwInit())
+		return false;
+
+	// Set window hints for OpenGL 3.3 Core context creation.
+	glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
+	glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
+	glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
+	glfwWindowHint(GLFW_DOUBLEBUFFER, GLFW_TRUE);
+
+	// Request stencil buffer of at least 8-bit size to supporting clipping on transformed elements.
+	glfwWindowHint(GLFW_STENCIL_BITS, 8);
+
+	// Enable MSAA for better-looking visuals, especially when transforms are applied.
+	glfwWindowHint(GLFW_SAMPLES, 2);
+
+	// Apply window properties and create it.
+	glfwWindowHint(GLFW_RESIZABLE, allow_resize ? GLFW_TRUE : GLFW_FALSE);
+	glfwWindowHint(GLFW_SCALE_TO_MONITOR, GLFW_TRUE);
+
+	GLFWwindow* window = glfwCreateWindow(width, height, name, nullptr, nullptr);
+	if (!window)
+		return false;
+
+	glfwMakeContextCurrent(window);
+	glfwSwapInterval(1);
+
+	// Load the OpenGL functions.
+	Rml::String renderer_message;
+	if (!RmlGL3::Initialize(&renderer_message))
+		return false;
+
+	// Construct the system and render interface, this includes compiling all the shaders. If this fails, it is likely an error in the shader code.
+	data = Rml::MakeUnique<BackendData>();
+	if (!data || !data->render_interface)
+		return false;
+
+	data->window = window;
+	data->system_interface.SetWindow(window);
+	data->system_interface.LogMessage(Rml::Log::LT_INFO, renderer_message);
+
+	// The window size may have been scaled by DPI settings, get the actual pixel size.
+	glfwGetFramebufferSize(window, &width, &height);
+	data->render_interface.SetViewport(width, height);
+
+	// Setup the input and window event callback functions.
+	SetupCallbacks(window);
+
+	return true;
+}
+
+void Backend::Shutdown()
+{
+	RMLUI_ASSERT(data);
+	glfwDestroyWindow(data->window);
+	data.reset();
+	RmlGL3::Shutdown();
+	glfwTerminate();
+}
+
+Rml::SystemInterface* Backend::GetSystemInterface()
+{
+	RMLUI_ASSERT(data);
+	return &data->system_interface;
+}
+
+Rml::RenderInterface* Backend::GetRenderInterface()
+{
+	RMLUI_ASSERT(data);
+	return &data->render_interface;
+}
+
+bool Backend::ProcessEvents(Rml::Context* context, KeyDownCallback key_down_callback)
+{
+	RMLUI_ASSERT(data && context);
+
+	// The initial window size may have been affected by system DPI settings, apply the actual pixel size and dp-ratio to the context.
+	if (data->context_dimensions_dirty)
+	{
+		data->context_dimensions_dirty = false;
+
+		Rml::Vector2i window_size;
+		float dp_ratio = 1.f;
+		glfwGetFramebufferSize(data->window, &window_size.x, &window_size.y);
+		glfwGetWindowContentScale(data->window, &dp_ratio, nullptr);
+
+		context->SetDimensions(window_size);
+		context->SetDensityIndependentPixelRatio(dp_ratio);
+	}
+
+	data->context = context;
+	data->key_down_callback = key_down_callback;
+
+	glfwPollEvents();
+
+	data->context = nullptr;
+	data->key_down_callback = nullptr;
+
+	return !glfwWindowShouldClose(data->window);
+}
+
+void Backend::RequestExit()
+{
+	RMLUI_ASSERT(data);
+	glfwSetWindowShouldClose(data->window, GLFW_TRUE);
+}
+
+void Backend::BeginFrame()
+{
+	RMLUI_ASSERT(data);
+	data->render_interface.BeginFrame();
+	data->render_interface.Clear();
+}
+
+void Backend::PresentFrame()
+{
+	RMLUI_ASSERT(data);
+	data->render_interface.EndFrame();
+	glfwSwapBuffers(data->window);
+
+	// Optional, used to mark frames during performance profiling.
+	RMLUI_FrameMark;
+}
+
+static void SetupCallbacks(GLFWwindow* window)
+{
+	RMLUI_ASSERT(data);
+
+	// Key input
+	glfwSetKeyCallback(window, [](GLFWwindow* /*window*/, int glfw_key, int /*scancode*/, int glfw_action, int glfw_mods) {
+		if (!data->context)
+			return;
+
+		// Store the active modifiers for later because GLFW doesn't provide them in the callbacks to the mouse input events.
+		data->glfw_active_modifiers = glfw_mods;
+
+		// Override the default key event callback to add global shortcuts for the samples.
+		Rml::Context* context = data->context;
+		KeyDownCallback key_down_callback = data->key_down_callback;
+
+		switch (glfw_action)
+		{
+		case GLFW_PRESS:
+		case GLFW_REPEAT:
+		{
+			const Rml::Input::KeyIdentifier key = RmlGLFW::ConvertKey(glfw_key);
+			const int key_modifier = RmlGLFW::ConvertKeyModifiers(glfw_mods);
+			float dp_ratio = 1.f;
+			glfwGetWindowContentScale(data->window, &dp_ratio, nullptr);
+
+			// See if we have any global shortcuts that take priority over the context.
+			if (key_down_callback && !key_down_callback(context, key, key_modifier, dp_ratio, true))
+				break;
+			// Otherwise, hand the event over to the context by calling the input handler as normal.
+			if (!RmlGLFW::ProcessKeyCallback(context, glfw_key, glfw_action, glfw_mods))
+				break;
+			// The key was not consumed by the context either, try keyboard shortcuts of lower priority.
+			if (key_down_callback && !key_down_callback(context, key, key_modifier, dp_ratio, false))
+				break;
+		}
+		break;
+		case GLFW_RELEASE:
+			RmlGLFW::ProcessKeyCallback(context, glfw_key, glfw_action, glfw_mods);
+			break;
+		}
+	});
+
+	glfwSetCharCallback(window, [](GLFWwindow* /*window*/, unsigned int codepoint) { RmlGLFW::ProcessCharCallback(data->context, codepoint); });
+
+	// Mouse input
+	glfwSetCursorPosCallback(window, [](GLFWwindow* /*window*/, double xpos, double ypos) {
+		RmlGLFW::ProcessCursorPosCallback(data->context, xpos, ypos, data->glfw_active_modifiers);
+	});
+
+	glfwSetMouseButtonCallback(window, [](GLFWwindow* /*window*/, int button, int action, int mods) {
+		data->glfw_active_modifiers = mods;
+		RmlGLFW::ProcessMouseButtonCallback(data->context, button, action, mods);
+	});
+
+	glfwSetScrollCallback(window, [](GLFWwindow* /*window*/, double /*xoffset*/, double yoffset) {
+		RmlGLFW::ProcessScrollCallback(data->context, yoffset, data->glfw_active_modifiers);
+	});
+
+	// Window events
+	glfwSetFramebufferSizeCallback(window, [](GLFWwindow* /*window*/, int width, int height) {
+		data->render_interface.SetViewport(width, height);
+		RmlGLFW::ProcessFramebufferSizeCallback(data->context, width, height);
+	});
+
+	glfwSetWindowContentScaleCallback(window,
+		[](GLFWwindow* /*window*/, float xscale, float /*yscale*/) { RmlGLFW::ProcessContentScaleCallback(data->context, xscale); });
+}

+ 340 - 0
Backends/RmlUi_Backend_SDL_GL2.cpp

@@ -0,0 +1,340 @@
+/*
+ * This source file is part of RmlUi, the HTML/CSS Interface Middleware
+ *
+ * For the latest information, see http://github.com/mikke89/RmlUi
+ *
+ * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd
+ * Copyright (c) 2019 The RmlUi Team, and contributors
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ */
+
+#include "RmlUi_Backend.h"
+#include "RmlUi_Platform_SDL.h"
+#include "RmlUi_Renderer_GL2.h"
+#include <RmlUi/Core/Context.h>
+#include <RmlUi/Core/Core.h>
+#include <RmlUi/Core/FileInterface.h>
+#include <GL/glew.h>
+#include <SDL.h>
+#include <SDL_image.h>
+
+#if !(SDL_VIDEO_RENDER_OGL)
+	#error "Only the OpenGL SDL backend is supported."
+#endif
+
+/**
+    Custom render interface example for the SDL/GL2 backend.
+
+    Overloads the OpenGL2 render interface to load textures through SDL_image's built-in texture loading functionality.
+ */
+class RenderInterface_GL2_SDL : public RenderInterface_GL2 {
+private:
+	SDL_Renderer* renderer;
+
+public:
+	RenderInterface_GL2_SDL(SDL_Renderer* renderer) : renderer(renderer) {}
+
+	void RenderGeometry(Rml::Vertex* vertices, int num_vertices, int* indices, int num_indices, Rml::TextureHandle texture,
+		const Rml::Vector2f& translation) override
+	{
+		SDL_Texture* sdl_texture = (SDL_Texture*)texture;
+		if (sdl_texture)
+		{
+			SDL_GL_BindTexture(sdl_texture, nullptr, nullptr);
+			texture = RenderInterface_GL2::TextureEnableWithoutBinding;
+		}
+
+		RenderInterface_GL2::RenderGeometry(vertices, num_vertices, indices, num_indices, texture, translation);
+
+		if (sdl_texture)
+			SDL_GL_UnbindTexture(sdl_texture);
+	}
+
+	bool LoadTexture(Rml::TextureHandle& texture_handle, Rml::Vector2i& texture_dimensions, const Rml::String& source) override
+	{
+		Rml::FileInterface* file_interface = Rml::GetFileInterface();
+		Rml::FileHandle file_handle = file_interface->Open(source);
+		if (!file_handle)
+			return false;
+
+		file_interface->Seek(file_handle, 0, SEEK_END);
+		size_t buffer_size = file_interface->Tell(file_handle);
+		file_interface->Seek(file_handle, 0, SEEK_SET);
+
+		char* buffer = new char[buffer_size];
+		file_interface->Read(buffer, buffer_size, file_handle);
+		file_interface->Close(file_handle);
+
+		const size_t i = source.rfind('.');
+		Rml::String extension = (i == Rml::String::npos ? Rml::String() : source.substr(i + 1));
+
+		SDL_Surface* surface = IMG_LoadTyped_RW(SDL_RWFromMem(buffer, int(buffer_size)), 1, extension.c_str());
+
+		bool success = false;
+
+		if (surface)
+		{
+			SDL_Texture* texture = SDL_CreateTextureFromSurface(renderer, surface);
+
+			if (texture)
+			{
+				texture_handle = (Rml::TextureHandle)texture;
+				texture_dimensions = Rml::Vector2i(surface->w, surface->h);
+				success = true;
+			}
+
+			SDL_FreeSurface(surface);
+		}
+
+		delete[] buffer;
+
+		return success;
+	}
+	bool GenerateTexture(Rml::TextureHandle& texture_handle, const Rml::byte* source, const Rml::Vector2i& source_dimensions) override
+	{
+#if SDL_BYTEORDER == SDL_BIG_ENDIAN
+		Uint32 rmask = 0xff000000;
+		Uint32 gmask = 0x00ff0000;
+		Uint32 bmask = 0x0000ff00;
+		Uint32 amask = 0x000000ff;
+#else
+		Uint32 rmask = 0x000000ff;
+		Uint32 gmask = 0x0000ff00;
+		Uint32 bmask = 0x00ff0000;
+		Uint32 amask = 0xff000000;
+#endif
+
+		SDL_Surface* surface = SDL_CreateRGBSurfaceFrom((void*)source, source_dimensions.x, source_dimensions.y, 32, source_dimensions.x * 4, rmask,
+			gmask, bmask, amask);
+		SDL_Texture* texture = SDL_CreateTextureFromSurface(renderer, surface);
+		SDL_SetTextureBlendMode(texture, SDL_BLENDMODE_BLEND);
+		SDL_FreeSurface(surface);
+		texture_handle = (Rml::TextureHandle)texture;
+		return true;
+	}
+
+	void ReleaseTexture(Rml::TextureHandle texture_handle) override { SDL_DestroyTexture((SDL_Texture*)texture_handle); }
+};
+
+/**
+    Global data used by this backend.
+
+    Lifetime governed by the calls to Backend::Initialize() and Backend::Shutdown().
+ */
+struct BackendData {
+	BackendData(SDL_Renderer* renderer) : render_interface(renderer) {}
+
+	SystemInterface_SDL system_interface;
+	RenderInterface_GL2_SDL render_interface;
+
+	SDL_Window* window = nullptr;
+	SDL_Renderer* renderer = nullptr;
+	SDL_GLContext glcontext = nullptr;
+
+	bool running = true;
+};
+static Rml::UniquePtr<BackendData> data;
+
+bool Backend::Initialize(const char* window_name, int width, int height, bool allow_resize)
+{
+	RMLUI_ASSERT(!data);
+
+	if (SDL_Init(SDL_INIT_VIDEO) != 0)
+		return false;
+
+	// Request stencil buffer of at least 8-bit size to supporting clipping on transformed elements.
+	SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, 8);
+	SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
+
+	// Enable linear filtering and MSAA for better-looking visuals, especially when transforms are applied.
+	SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "linear");
+	SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, 1);
+	SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, 2);
+
+	const Uint32 window_flags = (SDL_WINDOW_OPENGL | (allow_resize ? SDL_WINDOW_RESIZABLE : 0));
+
+	SDL_Window* window = SDL_CreateWindow(window_name, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, width, height, window_flags);
+	if (!window)
+	{
+		// Try again on low-quality settings.
+		SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "nearest");
+		SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, 0);
+		SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, 0);
+		window = SDL_CreateWindow(window_name, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, width, height, window_flags);
+		if (!window)
+		{
+			fprintf(stderr, "SDL error on create window: %s\n", SDL_GetError());
+			return false;
+		}
+	}
+
+	SDL_GLContext glcontext = SDL_GL_CreateContext(window);
+	int opengl_renderer_index = -1;
+	int num_render_drivers = SDL_GetNumRenderDrivers();
+	for (int i = 0; i < num_render_drivers; i++)
+	{
+		SDL_RendererInfo info;
+		if (SDL_GetRenderDriverInfo(i, &info) == 0)
+		{
+			if (strcmp(info.name, "opengl") == 0)
+				opengl_renderer_index = i;
+		}
+	}
+
+	SDL_Renderer* renderer = SDL_CreateRenderer(window, opengl_renderer_index, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC);
+	if (!renderer)
+		return false;
+
+	GLenum err = glewInit();
+	if (err != GLEW_OK)
+	{
+		fprintf(stderr, "GLEW error: %s\n", glewGetErrorString(err));
+		return false;
+	}
+
+	data = Rml::MakeUnique<BackendData>(renderer);
+
+	data->window = window;
+	data->glcontext = glcontext;
+	data->renderer = renderer;
+
+	data->system_interface.SetWindow(window);
+	data->render_interface.SetViewport(width, height);
+
+	return true;
+}
+
+void Backend::Shutdown()
+{
+	RMLUI_ASSERT(data);
+
+	SDL_DestroyRenderer(data->renderer);
+	SDL_GL_DeleteContext(data->glcontext);
+	SDL_DestroyWindow(data->window);
+
+	data.reset();
+
+	SDL_Quit();
+}
+
+Rml::SystemInterface* Backend::GetSystemInterface()
+{
+	RMLUI_ASSERT(data);
+	return &data->system_interface;
+}
+
+Rml::RenderInterface* Backend::GetRenderInterface()
+{
+	RMLUI_ASSERT(data);
+	return &data->render_interface;
+}
+
+bool Backend::ProcessEvents(Rml::Context* context, KeyDownCallback key_down_callback)
+{
+	RMLUI_ASSERT(data && context);
+
+	bool result = data->running;
+	SDL_Event ev;
+
+	while (SDL_PollEvent(&ev))
+	{
+		switch (ev.type)
+		{
+		case SDL_QUIT:
+		{
+			result = false;
+		}
+		break;
+		case SDL_KEYDOWN:
+		{
+			const Rml::Input::KeyIdentifier key = RmlSDL::ConvertKey(ev.key.keysym.sym);
+			const int key_modifier = RmlSDL::GetKeyModifierState();
+			const float native_dp_ratio = 1.f;
+
+			// See if we have any global shortcuts that take priority over the context.
+			if (key_down_callback && !key_down_callback(context, key, key_modifier, native_dp_ratio, true))
+				break;
+			// Otherwise, hand the event over to the context by calling the input handler as normal.
+			if (!RmlSDL::InputEventHandler(context, ev))
+				break;
+			// The key was not consumed by the context either, try keyboard shortcuts of lower priority.
+			if (key_down_callback && !key_down_callback(context, key, key_modifier, native_dp_ratio, false))
+				break;
+		}
+		break;
+		case SDL_WINDOWEVENT:
+		{
+			switch (ev.window.event)
+			{
+			case SDL_WINDOWEVENT_SIZE_CHANGED:
+			{
+				Rml::Vector2i dimensions(ev.window.data1, ev.window.data2);
+				context->SetDimensions(dimensions);
+				data->render_interface.SetViewport(dimensions.x, dimensions.y);
+			}
+			break;
+			}
+		}
+		break;
+		default:
+		{
+			RmlSDL::InputEventHandler(context, ev);
+		}
+		break;
+		}
+	}
+
+	return result;
+}
+
+void Backend::RequestExit()
+{
+	RMLUI_ASSERT(data);
+
+	data->running = false;
+}
+
+void Backend::BeginFrame()
+{
+	RMLUI_ASSERT(data);
+
+	SDL_SetRenderDrawColor(data->renderer, 0, 0, 0, 0);
+	SDL_RenderClear(data->renderer);
+
+	// SDL uses shaders that we need to disable here.
+	glUseProgramObjectARB(0);
+	glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
+
+	data->render_interface.BeginFrame();
+}
+
+void Backend::PresentFrame()
+{
+	RMLUI_ASSERT(data);
+
+	data->render_interface.EndFrame();
+
+	// Draw a fake point just outside the screen to let SDL know that it needs to reset its state in case it wants to render a texture next frame.
+	SDL_SetRenderDrawBlendMode(data->renderer, SDL_BLENDMODE_NONE);
+	SDL_RenderDrawPoint(data->renderer, -1, -1);
+
+	SDL_RenderPresent(data->renderer);
+}

+ 314 - 0
Backends/RmlUi_Backend_SDL_GL3.cpp

@@ -0,0 +1,314 @@
+/*
+ * This source file is part of RmlUi, the HTML/CSS Interface Middleware
+ *
+ * For the latest information, see http://github.com/mikke89/RmlUi
+ *
+ * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd
+ * Copyright (c) 2019 The RmlUi Team, and contributors
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ */
+
+#include "RmlUi_Backend.h"
+#include "RmlUi_Platform_SDL.h"
+#include "RmlUi_Renderer_GL3.h"
+#include <RmlUi/Core/Context.h>
+#include <RmlUi/Core/Core.h>
+#include <RmlUi/Core/FileInterface.h>
+#include <SDL.h>
+#include <SDL_image.h>
+
+#if defined RMLUI_PLATFORM_EMSCRIPTEN
+	#include <emscripten.h>
+#else
+	#if !(SDL_VIDEO_RENDER_OGL)
+		#error "Only the OpenGL SDL backend is supported."
+	#endif
+#endif
+
+/**
+    Custom render interface example for the SDL/GL3 backend.
+
+    Overloads the OpenGL3 render interface to load textures through SDL_image's built-in texture loading functionality.
+ */
+class RenderInterface_GL3_SDL : public RenderInterface_GL3 {
+public:
+	RenderInterface_GL3_SDL() {}
+
+	bool LoadTexture(Rml::TextureHandle& texture_handle, Rml::Vector2i& texture_dimensions, const Rml::String& source) override
+	{
+		Rml::FileInterface* file_interface = Rml::GetFileInterface();
+		Rml::FileHandle file_handle = file_interface->Open(source);
+		if (!file_handle)
+			return false;
+
+		file_interface->Seek(file_handle, 0, SEEK_END);
+		const size_t buffer_size = file_interface->Tell(file_handle);
+		file_interface->Seek(file_handle, 0, SEEK_SET);
+
+		using Rml::byte;
+		Rml::UniquePtr<byte[]> buffer(new byte[buffer_size]);
+		file_interface->Read(buffer.get(), buffer_size, file_handle);
+		file_interface->Close(file_handle);
+
+		const size_t i = source.rfind('.');
+		Rml::String extension = (i == Rml::String::npos ? Rml::String() : source.substr(i + 1));
+
+		SDL_Surface* surface = IMG_LoadTyped_RW(SDL_RWFromMem(buffer.get(), int(buffer_size)), 1, extension.c_str());
+
+		bool success = false;
+		if (surface)
+		{
+			texture_dimensions.x = surface->w;
+			texture_dimensions.y = surface->h;
+
+			if (surface->format->format != SDL_PIXELFORMAT_RGBA32)
+			{
+				SDL_SetSurfaceAlphaMod(surface, SDL_ALPHA_OPAQUE);
+				SDL_SetSurfaceBlendMode(surface, SDL_BLENDMODE_NONE);
+
+				SDL_Surface* new_surface = SDL_CreateRGBSurfaceWithFormat(0, surface->w, surface->h, 32, SDL_PIXELFORMAT_RGBA32);
+				if (!new_surface)
+					return false;
+
+				if (SDL_BlitSurface(surface, 0, new_surface, 0) != 0)
+					return false;
+
+				SDL_FreeSurface(surface);
+				surface = new_surface;
+			}
+
+			success = RenderInterface_GL3::GenerateTexture(texture_handle, (const Rml::byte*)surface->pixels, texture_dimensions);
+			SDL_FreeSurface(surface);
+		}
+
+		return success;
+	}
+};
+
+/**
+    Global data used by this backend.
+
+    Lifetime governed by the calls to Backend::Initialize() and Backend::Shutdown().
+ */
+struct BackendData {
+	SystemInterface_SDL system_interface;
+	RenderInterface_GL3_SDL render_interface;
+
+	SDL_Window* window = nullptr;
+	SDL_GLContext glcontext = nullptr;
+
+	bool running = true;
+};
+static Rml::UniquePtr<BackendData> data;
+
+bool Backend::Initialize(const char* window_name, int width, int height, bool allow_resize)
+{
+	RMLUI_ASSERT(!data);
+
+	if (SDL_Init(SDL_INIT_VIDEO) != 0)
+		return false;
+
+#if defined RMLUI_PLATFORM_EMSCRIPTEN
+	// GLES 3.0 (WebGL 2.0)
+	SDL_GL_SetAttribute(SDL_GL_CONTEXT_FLAGS, 0);
+	SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_ES);
+	SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);
+	SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 0);
+#else
+	// GL 3.3 Core
+	SDL_GL_SetAttribute(SDL_GL_CONTEXT_FLAGS, 0);
+	SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);
+	SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);
+	SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 3);
+#endif
+
+	// Request stencil buffer of at least 8-bit size to supporting clipping on transformed elements.
+	SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, 8);
+	SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
+
+	// Enable linear filtering and MSAA for better-looking visuals, especially when transforms are applied.
+	SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "linear");
+	SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, 1);
+	SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, 2);
+
+	const Uint32 window_flags = (SDL_WINDOW_OPENGL | (allow_resize ? SDL_WINDOW_RESIZABLE : 0));
+
+	SDL_Window* window = SDL_CreateWindow(window_name, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, width, height, window_flags);
+	if (!window)
+	{
+		// Try again on low-quality settings.
+		SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "nearest");
+		SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, 0);
+		SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, 0);
+		window = SDL_CreateWindow(window_name, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, width, height, window_flags);
+		if (!window)
+		{
+			fprintf(stderr, "SDL error on create window: %s\n", SDL_GetError());
+			return false;
+		}
+	}
+
+	SDL_GLContext glcontext = SDL_GL_CreateContext(window);
+	SDL_GL_MakeCurrent(window, glcontext);
+	SDL_GL_SetSwapInterval(1);
+
+	if (!RmlGL3::Initialize())
+	{
+		fprintf(stderr, "Could not initialize OpenGL");
+		return false;
+	}
+
+	data = Rml::MakeUnique<BackendData>();
+
+	if (!data->render_interface)
+	{
+		data.reset();
+		fprintf(stderr, "Could not initialize OpenGL3 render interface.");
+		return false;
+	}
+
+	data->window = window;
+	data->glcontext = glcontext;
+
+	data->system_interface.SetWindow(window);
+	data->render_interface.SetViewport(width, height);
+
+	return true;
+}
+
+void Backend::Shutdown()
+{
+	RMLUI_ASSERT(data);
+
+	SDL_GL_DeleteContext(data->glcontext);
+	SDL_DestroyWindow(data->window);
+
+	data.reset();
+
+	SDL_Quit();
+}
+
+Rml::SystemInterface* Backend::GetSystemInterface()
+{
+	RMLUI_ASSERT(data);
+	return &data->system_interface;
+}
+
+Rml::RenderInterface* Backend::GetRenderInterface()
+{
+	RMLUI_ASSERT(data);
+	return &data->render_interface;
+}
+
+bool Backend::ProcessEvents(Rml::Context* context, KeyDownCallback key_down_callback)
+{
+	RMLUI_ASSERT(data && context);
+
+#if defined RMLUI_PLATFORM_EMSCRIPTEN
+
+	// Ideally we would hand over control of the main loop to emscripten:
+	//
+	//  // Hand over control of the main loop to the WebAssembly runtime.
+	//  emscripten_set_main_loop_arg(EventLoopIteration, (void*)user_data_handle, 0, true);
+	//
+	// The above is the recommended approach. However, as we don't control the main loop here we have to make due with another approach. Instead, use
+	// Asyncify to yield by sleeping.
+	// Important: Must be linked with option -sASYNCIFY
+	emscripten_sleep(1);
+
+#endif
+
+	bool result = data->running;
+	SDL_Event ev;
+
+	while (SDL_PollEvent(&ev))
+	{
+		switch (ev.type)
+		{
+		case SDL_QUIT:
+		{
+			result = false;
+		}
+		break;
+		case SDL_KEYDOWN:
+		{
+			const Rml::Input::KeyIdentifier key = RmlSDL::ConvertKey(ev.key.keysym.sym);
+			const int key_modifier = RmlSDL::GetKeyModifierState();
+			const float native_dp_ratio = 1.f;
+
+			// See if we have any global shortcuts that take priority over the context.
+			if (key_down_callback && !key_down_callback(context, key, key_modifier, native_dp_ratio, true))
+				break;
+			// Otherwise, hand the event over to the context by calling the input handler as normal.
+			if (!RmlSDL::InputEventHandler(context, ev))
+				break;
+			// The key was not consumed by the context either, try keyboard shortcuts of lower priority.
+			if (key_down_callback && !key_down_callback(context, key, key_modifier, native_dp_ratio, false))
+				break;
+		}
+		break;
+		case SDL_WINDOWEVENT:
+		{
+			switch (ev.window.event)
+			{
+			case SDL_WINDOWEVENT_SIZE_CHANGED:
+			{
+				Rml::Vector2i dimensions(ev.window.data1, ev.window.data2);
+				context->SetDimensions(dimensions);
+				data->render_interface.SetViewport(dimensions.x, dimensions.y);
+			}
+			break;
+			}
+		}
+		break;
+		default:
+		{
+			RmlSDL::InputEventHandler(context, ev);
+		}
+		break;
+		}
+	}
+
+	return result;
+}
+
+void Backend::RequestExit()
+{
+	RMLUI_ASSERT(data);
+
+	data->running = false;
+}
+
+void Backend::BeginFrame()
+{
+	RMLUI_ASSERT(data);
+
+	data->render_interface.Clear();
+	data->render_interface.BeginFrame();
+}
+
+void Backend::PresentFrame()
+{
+	RMLUI_ASSERT(data);
+
+	data->render_interface.EndFrame();
+	SDL_GL_SwapWindow(data->window);
+}

+ 200 - 0
Backends/RmlUi_Backend_SDL_SDLrenderer.cpp

@@ -0,0 +1,200 @@
+/*
+ * This source file is part of RmlUi, the HTML/CSS Interface Middleware
+ *
+ * For the latest information, see http://github.com/mikke89/RmlUi
+ *
+ * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd
+ * Copyright (c) 2019 The RmlUi Team, and contributors
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ */
+
+#include "RmlUi_Backend.h"
+#include "RmlUi_Platform_SDL.h"
+#include "RmlUi_Renderer_SDL.h"
+#include <RmlUi/Core/Context.h>
+#include <RmlUi/Core/Core.h>
+#include <RmlUi/Core/Log.h>
+#include <SDL.h>
+
+/**
+    Global data used by this backend.
+
+    Lifetime governed by the calls to Backend::Initialize() and Backend::Shutdown().
+ */
+struct BackendData {
+	BackendData(SDL_Renderer* renderer) : render_interface(renderer) {}
+
+	SystemInterface_SDL system_interface;
+	RenderInterface_SDL render_interface;
+
+	SDL_Window* window = nullptr;
+	SDL_Renderer* renderer = nullptr;
+
+	bool running = true;
+};
+static Rml::UniquePtr<BackendData> data;
+
+bool Backend::Initialize(const char* window_name, int width, int height, bool allow_resize)
+{
+	RMLUI_ASSERT(!data);
+
+	if (SDL_Init(SDL_INIT_VIDEO) != 0)
+		return false;
+
+	const Uint32 window_flags = (allow_resize ? SDL_WINDOW_RESIZABLE : 0);
+	SDL_Window* window = SDL_CreateWindow(window_name, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, width, height, window_flags);
+	if (!window)
+	{
+		Rml::Log::Message(Rml::Log::LT_ERROR, "SDL error on create window: %s\n", SDL_GetError());
+		return false;
+	}
+
+	/*
+	 * Force a specific back-end
+	SDL_SetHint(SDL_HINT_RENDER_BATCHING, "1");
+	SDL_SetHint(SDL_HINT_RENDER_DRIVER, "software");
+	SDL_SetHint(SDL_HINT_RENDER_DRIVER, "opengles2");
+	SDL_SetHint(SDL_HINT_RENDER_DRIVER, "direct3d");
+	SDL_SetHint(SDL_HINT_RENDER_DRIVER, "opengl");
+	*/
+
+	SDL_Renderer* renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC);
+	if (!renderer)
+		return false;
+
+	data = Rml::MakeUnique<BackendData>(renderer);
+
+	data->window = window;
+	data->renderer = renderer;
+
+	data->system_interface.SetWindow(window);
+
+	SDL_RendererInfo renderer_info;
+	if (SDL_GetRendererInfo(renderer, &renderer_info) == 0)
+	{
+		data->system_interface.LogMessage(Rml::Log::LT_INFO, Rml::CreateString(128, "Using SDL renderer: %s\n", renderer_info.name));
+	}
+
+	return true;
+}
+
+void Backend::Shutdown()
+{
+	RMLUI_ASSERT(data);
+
+	SDL_DestroyRenderer(data->renderer);
+	SDL_DestroyWindow(data->window);
+
+	data.reset();
+
+	SDL_Quit();
+}
+
+Rml::SystemInterface* Backend::GetSystemInterface()
+{
+	RMLUI_ASSERT(data);
+	return &data->system_interface;
+}
+
+Rml::RenderInterface* Backend::GetRenderInterface()
+{
+	RMLUI_ASSERT(data);
+	return &data->render_interface;
+}
+
+bool Backend::ProcessEvents(Rml::Context* context, KeyDownCallback key_down_callback)
+{
+	RMLUI_ASSERT(data && context);
+
+	bool result = data->running;
+	SDL_Event ev;
+
+	while (SDL_PollEvent(&ev))
+	{
+		switch (ev.type)
+		{
+		case SDL_QUIT:
+		{
+			result = false;
+		}
+		break;
+		case SDL_KEYDOWN:
+		{
+			const Rml::Input::KeyIdentifier key = RmlSDL::ConvertKey(ev.key.keysym.sym);
+			const int key_modifier = RmlSDL::GetKeyModifierState();
+			const float native_dp_ratio = 1.f;
+
+			// See if we have any global shortcuts that take priority over the context.
+			if (key_down_callback && !key_down_callback(context, key, key_modifier, native_dp_ratio, true))
+				break;
+			// Otherwise, hand the event over to the context by calling the input handler as normal.
+			if (!RmlSDL::InputEventHandler(context, ev))
+				break;
+			// The key was not consumed by the context either, try keyboard shortcuts of lower priority.
+			if (key_down_callback && !key_down_callback(context, key, key_modifier, native_dp_ratio, false))
+				break;
+		}
+		break;
+		case SDL_WINDOWEVENT:
+		{
+			switch (ev.window.event)
+			{
+			case SDL_WINDOWEVENT_SIZE_CHANGED:
+				context->SetDimensions(Rml::Vector2i(ev.window.data1, ev.window.data2));
+				break;
+			}
+		}
+		break;
+		default:
+		{
+			RmlSDL::InputEventHandler(context, ev);
+		}
+		break;
+		}
+	}
+
+	return result;
+}
+
+void Backend::RequestExit()
+{
+	RMLUI_ASSERT(data);
+
+	data->running = false;
+}
+
+void Backend::BeginFrame()
+{
+	RMLUI_ASSERT(data);
+
+	SDL_SetRenderDrawColor(data->renderer, 0, 0, 0, 0);
+	SDL_RenderClear(data->renderer);
+
+	data->render_interface.BeginFrame();
+}
+
+void Backend::PresentFrame()
+{
+	RMLUI_ASSERT(data);
+
+	data->render_interface.EndFrame();
+	SDL_RenderPresent(data->renderer);
+}

+ 278 - 0
Backends/RmlUi_Backend_SFML_GL2.cpp

@@ -0,0 +1,278 @@
+/*
+ * This source file is part of RmlUi, the HTML/CSS Interface Middleware
+ *
+ * For the latest information, see http://github.com/mikke89/RmlUi
+ *
+ * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd
+ * Copyright (c) 2019 The RmlUi Team, and contributors
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ */
+
+#include "RmlUi_Backend.h"
+#include "RmlUi_Platform_SFML.h"
+#include "RmlUi_Renderer_GL2.h"
+#include <RmlUi/Core/Context.h>
+#include <RmlUi/Core/Core.h>
+#include <RmlUi/Core/FileInterface.h>
+#include <RmlUi/Core/Profiling.h>
+#include <RmlUi/Debugger/Debugger.h>
+#include <SFML/Graphics.hpp>
+#include <SFML/Window.hpp>
+
+/**
+    Custom render interface example for the SFML/GL2 backend.
+
+    Overloads the OpenGL2 render interface to load textures through SFML's built-in texture loading functionality.
+ */
+class RenderInterface_GL2_SFML : public RenderInterface_GL2 {
+public:
+	// -- Inherited from Rml::RenderInterface --
+
+	void RenderGeometry(Rml::Vertex* vertices, int num_vertices, int* indices, int num_indices, Rml::TextureHandle texture,
+		const Rml::Vector2f& translation) override
+	{
+		if (texture)
+		{
+			sf::Texture::bind((sf::Texture*)texture);
+			texture = RenderInterface_GL2::TextureEnableWithoutBinding;
+		}
+
+		RenderInterface_GL2::RenderGeometry(vertices, num_vertices, indices, num_indices, texture, translation);
+	}
+
+	bool LoadTexture(Rml::TextureHandle& texture_handle, Rml::Vector2i& texture_dimensions, const Rml::String& source) override
+	{
+		Rml::FileInterface* file_interface = Rml::GetFileInterface();
+		Rml::FileHandle file_handle = file_interface->Open(source);
+		if (!file_handle)
+			return false;
+
+		file_interface->Seek(file_handle, 0, SEEK_END);
+		size_t buffer_size = file_interface->Tell(file_handle);
+		file_interface->Seek(file_handle, 0, SEEK_SET);
+
+		char* buffer = new char[buffer_size];
+		file_interface->Read(buffer, buffer_size, file_handle);
+		file_interface->Close(file_handle);
+
+		sf::Texture* texture = new sf::Texture();
+		texture->setSmooth(true);
+
+		bool success = texture->loadFromMemory(buffer, buffer_size);
+
+		delete[] buffer;
+
+		if (success)
+		{
+			texture_handle = (Rml::TextureHandle)texture;
+			texture_dimensions = Rml::Vector2i(texture->getSize().x, texture->getSize().y);
+		}
+		else
+		{
+			delete texture;
+		}
+
+		return success;
+	}
+
+	bool GenerateTexture(Rml::TextureHandle& texture_handle, const Rml::byte* source, const Rml::Vector2i& source_dimensions) override
+	{
+		sf::Texture* texture = new sf::Texture();
+		texture->setSmooth(true);
+
+		if (!texture->create(source_dimensions.x, source_dimensions.y))
+		{
+			delete texture;
+			return false;
+		}
+
+		texture->update(source, source_dimensions.x, source_dimensions.y, 0, 0);
+		texture_handle = (Rml::TextureHandle)texture;
+
+		return true;
+	}
+
+	void ReleaseTexture(Rml::TextureHandle texture_handle) override { delete (sf::Texture*)texture_handle; }
+};
+
+// Updates the viewport and context dimensions, should be called whenever the window size changes.
+static void UpdateWindowDimensions(sf::RenderWindow& window, RenderInterface_GL2_SFML& render_interface, Rml::Context* context)
+{
+	const int width = (int)window.getSize().x;
+	const int height = (int)window.getSize().y;
+
+	if (context)
+		context->SetDimensions(Rml::Vector2i(width, height));
+
+	sf::View view(sf::FloatRect(0.f, 0.f, (float)width, (float)height));
+	window.setView(view);
+
+	render_interface.SetViewport(width, height);
+}
+
+/**
+    Global data used by this backend.
+
+    Lifetime governed by the calls to Backend::Initialize() and Backend::Shutdown().
+ */
+struct BackendData {
+	SystemInterface_SFML system_interface;
+	RenderInterface_GL2_SFML render_interface;
+	sf::RenderWindow window;
+	bool running = true;
+};
+static Rml::UniquePtr<BackendData> data;
+
+bool Backend::Initialize(const char* window_name, int width, int height, bool allow_resize)
+{
+	RMLUI_ASSERT(!data);
+
+	data = Rml::MakeUnique<BackendData>();
+
+	// Create the window.
+	sf::RenderWindow out_window;
+	sf::ContextSettings context_settings;
+	context_settings.stencilBits = 8;
+	context_settings.antialiasingLevel = 2;
+
+	const sf::Uint32 style = (allow_resize ? sf::Style::Default : (sf::Style::Titlebar | sf::Style::Close));
+
+	data->window.create(sf::VideoMode(width, height), window_name, style, context_settings);
+	data->window.setVerticalSyncEnabled(true);
+
+	if (!data->window.isOpen())
+	{
+		data.reset();
+		return false;
+	}
+
+	// Optionally apply the SFML window to the system interface so that it can change its mouse cursor.
+	data->system_interface.SetWindow(&data->window);
+
+	UpdateWindowDimensions(data->window, data->render_interface, nullptr);
+
+	return true;
+}
+
+void Backend::Shutdown()
+{
+	data.reset();
+}
+
+Rml::SystemInterface* Backend::GetSystemInterface()
+{
+	RMLUI_ASSERT(data);
+	return &data->system_interface;
+}
+
+Rml::RenderInterface* Backend::GetRenderInterface()
+{
+	RMLUI_ASSERT(data);
+	return &data->render_interface;
+}
+
+bool Backend::ProcessEvents(Rml::Context* context, KeyDownCallback key_down_callback)
+{
+	RMLUI_ASSERT(data && context);
+
+	// The contents of this function is intended to be copied directly into your main loop.
+	bool result = data->running;
+	sf::Event ev;
+
+	while (data->window.pollEvent(ev))
+	{
+		switch (ev.type)
+		{
+		case sf::Event::Resized:
+			UpdateWindowDimensions(data->window, data->render_interface, context);
+			break;
+		case sf::Event::KeyPressed:
+		{
+			const Rml::Input::KeyIdentifier key = RmlSFML::ConvertKey(ev.key.code);
+			const int key_modifier = RmlSFML::GetKeyModifierState();
+			const float native_dp_ratio = 1.f;
+
+			// See if we have any global shortcuts that take priority over the context.
+			if (key_down_callback && !key_down_callback(context, key, key_modifier, native_dp_ratio, true))
+				break;
+			// Otherwise, hand the event over to the context by calling the input handler as normal.
+			if (!RmlSFML::InputHandler(context, ev))
+				break;
+			// The key was not consumed by the context either, try keyboard shortcuts of lower priority.
+			if (key_down_callback && !key_down_callback(context, key, key_modifier, native_dp_ratio, false))
+				break;
+		}
+		break;
+		case sf::Event::Closed:
+			result = false;
+			break;
+		default:
+			RmlSFML::InputHandler(context, ev);
+			break;
+		}
+	}
+
+	return result;
+}
+
+void Backend::RequestExit()
+{
+	RMLUI_ASSERT(data);
+	data->running = false;
+}
+
+void Backend::BeginFrame()
+{
+	RMLUI_ASSERT(data);
+	sf::RenderWindow& window = data->window;
+
+	window.resetGLStates();
+	window.clear();
+
+	data->render_interface.BeginFrame();
+
+#if 0
+	// Draw a simple shape with SFML for demonstration purposes. Make sure to push and pop GL states as appropriate.
+	sf::Vector2f circle_position(100.f, 100.f);
+
+	window.pushGLStates();
+
+	sf::CircleShape circle(50.f);
+	circle.setPosition(circle_position);
+	circle.setFillColor(sf::Color::Blue);
+	circle.setOutlineColor(sf::Color::Red);
+	circle.setOutlineThickness(10.f);
+	window.draw(circle);
+
+	window.popGLStates();
+#endif
+}
+
+void Backend::PresentFrame()
+{
+	RMLUI_ASSERT(data);
+
+	data->render_interface.EndFrame();
+	data->window.display();
+
+	// Optional, used to mark frames during performance profiling.
+	RMLUI_FrameMark;
+}

+ 448 - 0
Backends/RmlUi_Backend_Win32_GL2.cpp

@@ -0,0 +1,448 @@
+/*
+ * This source file is part of RmlUi, the HTML/CSS Interface Middleware
+ *
+ * For the latest information, see http://github.com/mikke89/RmlUi
+ *
+ * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd
+ * Copyright (c) 2019 The RmlUi Team, and contributors
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ */
+
+#include "RmlUi_Backend.h"
+#include "RmlUi_Include_Windows.h"
+#include "RmlUi_Platform_Win32.h"
+#include "RmlUi_Renderer_GL2.h"
+#include <RmlUi/Core/Context.h>
+#include <RmlUi/Core/Core.h>
+#include <RmlUi/Core/Profiling.h>
+
+/**
+    High DPI support using Windows Per Monitor V2 DPI awareness.
+
+    Requires Windows 10, version 1703.
+ */
+#ifndef DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2
+	#define DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2 ((HANDLE)-4)
+#endif
+#ifndef WM_DPICHANGED
+	#define WM_DPICHANGED 0x02E0
+#endif
+
+// Declare pointers to the DPI aware Windows API functions.
+using ProcSetProcessDpiAwarenessContext = BOOL(WINAPI*)(HANDLE value);
+using ProcGetDpiForWindow = UINT(WINAPI*)(HWND hwnd);
+using ProcAdjustWindowRectExForDpi = BOOL(WINAPI*)(LPRECT lpRect, DWORD dwStyle, BOOL bMenu, DWORD dwExStyle, UINT dpi);
+
+static bool has_dpi_support = false;
+static ProcSetProcessDpiAwarenessContext procSetProcessDpiAwarenessContext = NULL;
+static ProcGetDpiForWindow procGetDpiForWindow = NULL;
+static ProcAdjustWindowRectExForDpi procAdjustWindowRectExForDpi = NULL;
+
+// Make ourselves DPI aware on supported Windows versions.
+static void InitializeDpiSupport()
+{
+	// Cast function pointers to void* first for MinGW not to emit errors.
+	procSetProcessDpiAwarenessContext =
+		(ProcSetProcessDpiAwarenessContext)(void*)GetProcAddress(GetModuleHandle(TEXT("User32.dll")), "SetProcessDpiAwarenessContext");
+	procGetDpiForWindow = (ProcGetDpiForWindow)(void*)GetProcAddress(GetModuleHandle(TEXT("User32.dll")), "GetDpiForWindow");
+	procAdjustWindowRectExForDpi =
+		(ProcAdjustWindowRectExForDpi)(void*)GetProcAddress(GetModuleHandle(TEXT("User32.dll")), "AdjustWindowRectExForDpi");
+
+	if (!has_dpi_support && procSetProcessDpiAwarenessContext != NULL && procGetDpiForWindow != NULL && procAdjustWindowRectExForDpi != NULL)
+	{
+		// Activate Per Monitor V2.
+		if (procSetProcessDpiAwarenessContext(DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2))
+			has_dpi_support = true;
+	}
+}
+
+static UINT GetWindowDpi(HWND window_handle)
+{
+	if (has_dpi_support)
+	{
+		UINT dpi = procGetDpiForWindow(window_handle);
+		if (dpi != 0)
+			return dpi;
+	}
+	return USER_DEFAULT_SCREEN_DPI;
+}
+
+static float GetDensityIndependentPixelRatio(HWND window_handle)
+{
+	return float(GetWindowDpi(window_handle)) / float(USER_DEFAULT_SCREEN_DPI);
+}
+
+static void DisplayError(HWND window_handle, const Rml::String& msg)
+{
+	MessageBoxW(window_handle, RmlWin32::ConvertToUTF16(msg).c_str(), L"Backend Error", MB_OK);
+}
+
+// Create the window but don't show it yet. Returns the pixel size of the window, which may be different than the passed size due to DPI settings.
+static HWND InitializeWindow(HINSTANCE instance_handle, const std::wstring& name, int& inout_width, int& inout_height, bool allow_resize);
+// Attach the OpenGL context.
+static bool AttachToNative(HWND window_handle, HDC& out_device_context, HGLRC& out_render_context);
+// Detach the OpenGL context.
+static void DetachFromNative(HWND window_handle, HDC device_context, HGLRC render_context);
+
+/**
+    Global data used by this backend.
+
+    Lifetime governed by the calls to Backend::Initialize() and Backend::Shutdown().
+ */
+struct BackendData {
+	SystemInterface_Win32 system_interface;
+	RenderInterface_GL2 render_interface;
+
+	HINSTANCE instance_handle = nullptr;
+	std::wstring instance_name;
+	HWND window_handle = nullptr;
+
+	HDC device_context = nullptr;
+	HGLRC render_context = nullptr;
+
+	bool context_dimensions_dirty = true;
+	Rml::Vector2i window_dimensions;
+	bool running = true;
+
+	// Arguments set during event processing and nulled otherwise.
+	Rml::Context* context = nullptr;
+	KeyDownCallback key_down_callback = nullptr;
+};
+static Rml::UniquePtr<BackendData> data;
+
+bool Backend::Initialize(const char* window_name, int width, int height, bool allow_resize)
+{
+	RMLUI_ASSERT(!data);
+
+	const std::wstring name = RmlWin32::ConvertToUTF16(Rml::String(window_name));
+
+	data = Rml::MakeUnique<BackendData>();
+
+	data->instance_handle = GetModuleHandle(nullptr);
+	data->instance_name = name;
+
+	InitializeDpiSupport();
+
+	// Initialize the window but don't show it yet.
+	HWND window_handle = InitializeWindow(data->instance_handle, name, width, height, allow_resize);
+	if (!window_handle)
+		return false;
+
+	// Attach the OpenGL context.
+	if (!AttachToNative(window_handle, data->device_context, data->render_context))
+	{
+		::CloseWindow(window_handle);
+		return false;
+	}
+
+	data->window_handle = window_handle;
+	data->system_interface.SetWindow(window_handle);
+
+	// Now we are ready to show the window.
+	::ShowWindow(window_handle, SW_SHOW);
+	::SetForegroundWindow(window_handle);
+	::SetFocus(window_handle);
+
+	return true;
+}
+
+void Backend::Shutdown()
+{
+	RMLUI_ASSERT(data);
+
+	DetachFromNative(data->window_handle, data->device_context, data->render_context);
+
+	::DestroyWindow(data->window_handle);
+	::UnregisterClassW((LPCWSTR)data->instance_name.data(), data->instance_handle);
+
+	data.reset();
+}
+
+Rml::SystemInterface* Backend::GetSystemInterface()
+{
+	RMLUI_ASSERT(data);
+	return &data->system_interface;
+}
+
+Rml::RenderInterface* Backend::GetRenderInterface()
+{
+	RMLUI_ASSERT(data);
+	return &data->render_interface;
+}
+
+bool Backend::ProcessEvents(Rml::Context* context, KeyDownCallback key_down_callback)
+{
+	RMLUI_ASSERT(data && context);
+
+	// The initial window size may have been affected by system DPI settings, apply the actual pixel size and dp-ratio to the context.
+	if (data->context_dimensions_dirty)
+	{
+		data->context_dimensions_dirty = false;
+		const float dp_ratio = GetDensityIndependentPixelRatio(data->window_handle);
+		context->SetDimensions(data->window_dimensions);
+		context->SetDensityIndependentPixelRatio(dp_ratio);
+	}
+
+	data->context = context;
+	data->key_down_callback = key_down_callback;
+
+	MSG message;
+	while (PeekMessage(&message, nullptr, 0, 0, PM_NOREMOVE))
+	{
+		GetMessage(&message, nullptr, 0, 0);
+
+		// Dispatch the message to our local event handler below.
+		TranslateMessage(&message);
+		DispatchMessage(&message);
+	}
+
+	data->context = nullptr;
+	data->key_down_callback = nullptr;
+
+	return data->running;
+}
+
+void Backend::RequestExit()
+{
+	RMLUI_ASSERT(data);
+	data->running = false;
+}
+
+void Backend::BeginFrame()
+{
+	RMLUI_ASSERT(data);
+	data->render_interface.BeginFrame();
+	data->render_interface.Clear();
+}
+
+void Backend::PresentFrame()
+{
+	RMLUI_ASSERT(data);
+	data->render_interface.EndFrame();
+
+	// Flips the OpenGL buffers.
+	SwapBuffers(data->device_context);
+
+	// Optional, used to mark frames during performance profiling.
+	RMLUI_FrameMark;
+}
+
+// Local event handler for window and input events.
+static LRESULT CALLBACK WindowProcedureHandler(HWND window_handle, UINT message, WPARAM w_param, LPARAM l_param)
+{
+	RMLUI_ASSERT(data);
+
+	switch (message)
+	{
+	case WM_CLOSE:
+	{
+		data->running = false;
+		return 0;
+	}
+	break;
+	case WM_SIZE:
+	{
+		// Intercept sizing to set the OpenGL viewport, then submit it to the platform handler for context sizing.
+		const int width = LOWORD(l_param);
+		const int height = HIWORD(l_param);
+		data->window_dimensions.x = width;
+		data->window_dimensions.y = height;
+		data->render_interface.SetViewport(width, height);
+		if (data->context)
+			data->context->SetDimensions(data->window_dimensions);
+		return 0;
+	}
+	break;
+	case WM_DPICHANGED:
+	{
+		RECT* new_pos = (RECT*)l_param;
+		SetWindowPos(window_handle, NULL, new_pos->left, new_pos->top, new_pos->right - new_pos->left, new_pos->bottom - new_pos->top,
+			SWP_NOZORDER | SWP_NOACTIVATE);
+		if (data->context && has_dpi_support)
+			data->context->SetDensityIndependentPixelRatio(GetDensityIndependentPixelRatio(window_handle));
+		return 0;
+	}
+	break;
+	case WM_KEYDOWN:
+	{
+		// Override the default key event callback to add global shortcuts for the samples.
+		Rml::Context* context = data->context;
+		KeyDownCallback key_down_callback = data->key_down_callback;
+
+		const Rml::Input::KeyIdentifier rml_key = RmlWin32::ConvertKey((int)w_param);
+		const int rml_modifier = RmlWin32::GetKeyModifierState();
+		const float native_dp_ratio = GetDensityIndependentPixelRatio(window_handle);
+
+		// See if we have any global shortcuts that take priority over the context.
+		if (key_down_callback && !key_down_callback(context, rml_key, rml_modifier, native_dp_ratio, true))
+			return 0;
+		// Otherwise, hand the event over to the context by calling the input handler as normal.
+		if (!RmlWin32::WindowProcedure(context, window_handle, message, w_param, l_param))
+			return 0;
+		// The key was not consumed by the context either, try keyboard shortcuts of lower priority.
+		if (key_down_callback && !key_down_callback(context, rml_key, rml_modifier, native_dp_ratio, false))
+			return 0;
+		return 0;
+	}
+	break;
+	default:
+	{
+		// Submit it to the platform handler for default input handling.
+		if (!RmlWin32::WindowProcedure(data->context, window_handle, message, w_param, l_param))
+			return 0;
+	}
+	break;
+	}
+
+	// All unhandled messages go to DefWindowProc.
+	return DefWindowProc(window_handle, message, w_param, l_param);
+}
+
+static HWND InitializeWindow(HINSTANCE instance_handle, const std::wstring& name, int& inout_width, int& inout_height, bool allow_resize)
+{
+	// Fill out the window class struct.
+	WNDCLASSW window_class;
+	window_class.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
+	window_class.lpfnWndProc = &WindowProcedureHandler; // Attach our local event handler.
+	window_class.cbClsExtra = 0;
+	window_class.cbWndExtra = 0;
+	window_class.hInstance = instance_handle;
+	window_class.hIcon = LoadIcon(nullptr, IDI_WINLOGO);
+	window_class.hCursor = LoadCursor(nullptr, IDC_ARROW);
+	window_class.hbrBackground = nullptr;
+	window_class.lpszMenuName = nullptr;
+	window_class.lpszClassName = name.data();
+
+	if (!RegisterClassW(&window_class))
+	{
+		DisplayError(NULL, "Could not register window class.");
+		return nullptr;
+	}
+
+	HWND window_handle = CreateWindowExW(WS_EX_APPWINDOW | WS_EX_WINDOWEDGE,
+		name.data(),                                                                // Window class name.
+		name.data(), WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_OVERLAPPEDWINDOW, 0, 0, // Window position.
+		0, 0,                                                                       // Window size.
+		nullptr, nullptr, instance_handle, nullptr);
+
+	if (!window_handle)
+	{
+		DisplayError(NULL, "Could not create window.");
+		return nullptr;
+	}
+
+	UINT window_dpi = GetWindowDpi(window_handle);
+	inout_width = (inout_width * (int)window_dpi) / USER_DEFAULT_SCREEN_DPI;
+	inout_height = (inout_height * (int)window_dpi) / USER_DEFAULT_SCREEN_DPI;
+
+	DWORD style = (allow_resize ? WS_OVERLAPPEDWINDOW : (WS_OVERLAPPEDWINDOW & ~WS_SIZEBOX & ~WS_MAXIMIZEBOX));
+	DWORD extended_style = WS_EX_APPWINDOW | WS_EX_WINDOWEDGE;
+
+	// Adjust the window size to take the edges into account.
+	RECT window_rect;
+	window_rect.top = 0;
+	window_rect.left = 0;
+	window_rect.right = inout_width;
+	window_rect.bottom = inout_height;
+	if (has_dpi_support)
+		procAdjustWindowRectExForDpi(&window_rect, style, FALSE, extended_style, window_dpi);
+	else
+		AdjustWindowRectEx(&window_rect, style, FALSE, extended_style);
+
+	SetWindowLong(window_handle, GWL_EXSTYLE, extended_style);
+	SetWindowLong(window_handle, GWL_STYLE, style);
+
+	// Resize the window.
+	SetWindowPos(window_handle, HWND_TOP, 0, 0, window_rect.right - window_rect.left, window_rect.bottom - window_rect.top, SWP_NOACTIVATE);
+
+	return window_handle;
+}
+
+static bool AttachToNative(HWND window_handle, HDC& out_device_context, HGLRC& out_render_context)
+{
+	HDC device_context = GetDC(window_handle);
+
+	if (!device_context)
+	{
+		DisplayError(window_handle, "Could not get device context.");
+		return false;
+	}
+
+	PIXELFORMATDESCRIPTOR pixel_format_descriptor = {};
+	pixel_format_descriptor.nSize = sizeof(PIXELFORMATDESCRIPTOR);
+	pixel_format_descriptor.nVersion = 1;
+	pixel_format_descriptor.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER;
+	pixel_format_descriptor.iPixelType = PFD_TYPE_RGBA;
+	pixel_format_descriptor.cColorBits = 32;
+	pixel_format_descriptor.cRedBits = 8;
+	pixel_format_descriptor.cGreenBits = 8;
+	pixel_format_descriptor.cBlueBits = 8;
+	pixel_format_descriptor.cAlphaBits = 8;
+	pixel_format_descriptor.cDepthBits = 24;
+	pixel_format_descriptor.cStencilBits = 8;
+
+	int pixel_format = ChoosePixelFormat(device_context, &pixel_format_descriptor);
+	if (!pixel_format)
+	{
+		DisplayError(window_handle, "Could not choose 32-bit pixel format.");
+		return false;
+	}
+
+	if (!SetPixelFormat(device_context, pixel_format, &pixel_format_descriptor))
+	{
+		DisplayError(window_handle, "Could not set pixel format.");
+		return false;
+	}
+
+	HGLRC render_context = wglCreateContext(device_context);
+	if (!render_context)
+	{
+		DisplayError(window_handle, "Could not create OpenGL rendering context.");
+		return false;
+	}
+
+	// Activate the rendering context.
+	if (!wglMakeCurrent(device_context, render_context))
+	{
+		DisplayError(window_handle, "Unable to make rendering context current.");
+		return false;
+	}
+
+	out_device_context = device_context;
+	out_render_context = render_context;
+
+	return true;
+}
+
+static void DetachFromNative(HWND window_handle, HDC device_context, HGLRC render_context)
+{
+	// Shutdown OpenGL
+	if (render_context)
+	{
+		wglMakeCurrent(nullptr, nullptr);
+		wglDeleteContext(render_context);
+	}
+
+	if (device_context)
+	{
+		ReleaseDC(window_handle, device_context);
+	}
+}

+ 294 - 0
Backends/RmlUi_Backend_X11_GL2.cpp

@@ -0,0 +1,294 @@
+/*
+ * This source file is part of RmlUi, the HTML/CSS Interface Middleware
+ *
+ * For the latest information, see http://github.com/mikke89/RmlUi
+ *
+ * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd
+ * Copyright (c) 2019 The RmlUi Team, and contributors
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ */
+
+#include "RmlUi_Backend.h"
+#include "RmlUi_Include_Xlib.h"
+#include "RmlUi_Platform_X11.h"
+#include "RmlUi_Renderer_GL2.h"
+#include <RmlUi/Core/Context.h>
+#include <GL/gl.h>
+#include <GL/glext.h>
+#include <GL/glu.h>
+#include <GL/glx.h>
+#include <X11/Xlib.h>
+#include <X11/cursorfont.h>
+#include <X11/extensions/xf86vmode.h>
+#include <limits.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <time.h>
+#include <unistd.h>
+
+// Attach the OpenGL context to the window.
+static bool AttachToNative(GLXContext& out_gl_context, Display* display, Window window, XVisualInfo* visual_info)
+{
+	GLXContext gl_context = glXCreateContext(display, visual_info, nullptr, GL_TRUE);
+	if (!gl_context)
+		return false;
+
+	if (!glXMakeCurrent(display, window, gl_context))
+		return false;
+
+	if (!glXIsDirect(display, gl_context))
+		puts("OpenGL context does not support direct rendering; performance is likely to be poor.");
+
+	out_gl_context = gl_context;
+
+	Window root_window;
+	int x, y;
+	unsigned int width, height;
+	unsigned int border_width, depth;
+	XGetGeometry(display, window, &root_window, &x, &y, &width, &height, &border_width, &depth);
+
+	return true;
+}
+
+// Shutdown the OpenGL context.
+static void DetachFromNative(GLXContext gl_context, Display* display)
+{
+	glXMakeCurrent(display, 0L, nullptr);
+	glXDestroyContext(display, gl_context);
+}
+
+/**
+    Global data used by this backend.
+
+    Lifetime governed by the calls to Backend::Initialize() and Backend::Shutdown().
+ */
+struct BackendData {
+	BackendData(Display* display) : system_interface(display) {}
+
+	SystemInterface_X11 system_interface;
+	RenderInterface_GL2 render_interface;
+
+	Display* display = nullptr;
+	Window window = 0;
+	GLXContext gl_context = nullptr;
+
+	bool running = true;
+};
+static Rml::UniquePtr<BackendData> data;
+
+bool Backend::Initialize(const char* window_name, int width, int height, bool allow_resize)
+{
+	RMLUI_ASSERT(!data);
+
+	Display* display = XOpenDisplay(0);
+	if (!display)
+		return false;
+
+	int screen = XDefaultScreen(display);
+
+	// Fetch an appropriate 32-bit visual interface.
+	int attribute_list[] = {GLX_RGBA, GLX_DOUBLEBUFFER, GLX_RED_SIZE, 8, GLX_GREEN_SIZE, 8, GLX_BLUE_SIZE, 8, GLX_DEPTH_SIZE, 24, GLX_STENCIL_SIZE, 8,
+		0L};
+
+	XVisualInfo* visual_info = glXChooseVisual(display, screen, attribute_list);
+	if (!visual_info)
+		return false;
+
+	// Build up our window attributes.
+	XSetWindowAttributes window_attributes;
+	window_attributes.colormap = XCreateColormap(display, RootWindow(display, visual_info->screen), visual_info->visual, AllocNone);
+	window_attributes.border_pixel = 0;
+	window_attributes.event_mask = ExposureMask | KeyPressMask | ButtonPressMask | StructureNotifyMask;
+
+	// Create the window.
+	Window window = XCreateWindow(display, RootWindow(display, visual_info->screen), 0, 0, width, height, 0, visual_info->depth, InputOutput,
+		visual_info->visual, CWBorderPixel | CWColormap | CWEventMask, &window_attributes);
+
+	// Handle delete events in windowed mode.
+	Atom delete_atom = XInternAtom(display, "WM_DELETE_WINDOW", True);
+	XSetWMProtocols(display, window, &delete_atom, 1);
+
+	// Capture the events we're interested in.
+	XSelectInput(display, window, KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask | PointerMotionMask | StructureNotifyMask);
+
+	if (!allow_resize)
+	{
+		// Force the window to remain at the fixed size by asking the window manager nicely, it may choose to ignore us
+		XSizeHints* win_size_hints = XAllocSizeHints(); // Allocate a size hint structure
+		if (!win_size_hints)
+		{
+			fprintf(stderr, "XAllocSizeHints - out of memory\n");
+		}
+		else
+		{
+			// Initialize the structure and specify which hints will be providing
+			win_size_hints->flags = PSize | PMinSize | PMaxSize;
+
+			// Set the sizes we want the window manager to use
+			win_size_hints->base_width = width;
+			win_size_hints->base_height = height;
+			win_size_hints->min_width = width;
+			win_size_hints->min_height = height;
+			win_size_hints->max_width = width;
+			win_size_hints->max_height = height;
+
+			// Pass the size hints to the window manager.
+			XSetWMNormalHints(display, window, win_size_hints);
+
+			// Free the size buffer
+			XFree(win_size_hints);
+		}
+	}
+
+	// Set the window title and show the window.
+	XSetStandardProperties(display, window, window_name, "", 0L, nullptr, 0, nullptr);
+	XMapRaised(display, window);
+
+	GLXContext gl_context = {};
+	if (!AttachToNative(gl_context, display, window, visual_info))
+		return false;
+
+	data = Rml::MakeUnique<BackendData>(display);
+
+	data->display = display;
+	data->window = window;
+	data->gl_context = gl_context;
+
+	data->system_interface.SetWindow(window);
+	data->render_interface.SetViewport(width, height);
+
+	return true;
+}
+
+void Backend::Shutdown()
+{
+	RMLUI_ASSERT(data);
+
+	DetachFromNative(data->gl_context, data->display);
+	XCloseDisplay(data->display);
+
+	data.reset();
+}
+
+Rml::SystemInterface* Backend::GetSystemInterface()
+{
+	RMLUI_ASSERT(data);
+	return &data->system_interface;
+}
+
+Rml::RenderInterface* Backend::GetRenderInterface()
+{
+	RMLUI_ASSERT(data);
+	return &data->render_interface;
+}
+
+bool Backend::ProcessEvents(Rml::Context* context, KeyDownCallback key_down_callback)
+{
+	RMLUI_ASSERT(data && context);
+
+	Display* display = data->display;
+	bool result = data->running;
+
+	while (XPending(display) > 0)
+	{
+		XEvent ev;
+		XNextEvent(display, &ev);
+
+		switch (ev.type)
+		{
+		case ClientMessage:
+		{
+			// The only message we register for is WM_DELETE_WINDOW, so if we receive a client message then the window has been closed.
+			char* event_type = XGetAtomName(display, ev.xclient.message_type);
+			if (strcmp(event_type, "WM_PROTOCOLS") == 0)
+				data->running = false;
+			XFree(event_type);
+			event_type = nullptr;
+		}
+		break;
+		case ConfigureNotify:
+		{
+			int x = ev.xconfigure.width;
+			int y = ev.xconfigure.height;
+
+			context->SetDimensions({x, y});
+			data->render_interface.SetViewport(x, y);
+		}
+		break;
+		case KeyPress:
+		{
+			Rml::Input::KeyIdentifier key = RmlX11::ConvertKey(display, ev.xkey.keycode);
+			const int key_modifier = RmlX11::GetKeyModifierState(ev.xkey.state);
+			const float native_dp_ratio = 1.f;
+
+			// See if we have any global shortcuts that take priority over the context.
+			if (key_down_callback && !key_down_callback(context, key, key_modifier, native_dp_ratio, true))
+				break;
+			// Otherwise, hand the event over to the context by calling the input handler as normal.
+			if (!RmlX11::HandleInputEvent(context, display, ev))
+				break;
+			// The key was not consumed by the context either, try keyboard shortcuts of lower priority.
+			if (key_down_callback && !key_down_callback(context, key, key_modifier, native_dp_ratio, false))
+				break;
+		}
+		break;
+		case SelectionRequest:
+		{
+			data->system_interface.HandleSelectionRequest(ev);
+		}
+		break;
+		default:
+		{
+			// Pass unhandled events to the platform layer's input handler.
+			RmlX11::HandleInputEvent(context, display, ev);
+		}
+		break;
+		}
+	}
+
+	return result;
+}
+
+void Backend::RequestExit()
+{
+	RMLUI_ASSERT(data);
+	data->running = false;
+}
+
+void Backend::BeginFrame()
+{
+	RMLUI_ASSERT(data);
+	data->render_interface.BeginFrame();
+	data->render_interface.Clear();
+}
+
+void Backend::PresentFrame()
+{
+	RMLUI_ASSERT(data);
+	data->render_interface.EndFrame();
+
+	// Flips the OpenGL buffers.
+	glXSwapBuffers(data->display, data->window);
+}

+ 3582 - 0
Backends/RmlUi_Include_GL3.h

@@ -0,0 +1,3582 @@
+/**
+ * Loader generated by glad 2.0.0-beta on Fri Mar 11 10:53:06 2022
+ *
+ * Generator: C/C++
+ * Specification: gl
+ * Extensions: 0
+ *
+ * APIs:
+ *  - gl:core=3.3
+ *
+ * Options:
+ *  - ALIAS = False
+ *  - DEBUG = False
+ *  - HEADER_ONLY = True
+ *  - LOADER = True
+ *  - MX = False
+ *  - MX_GLOBAL = False
+ *  - ON_DEMAND = False
+ *
+ * Commandline:
+ *    --api='gl:core=3.3' --extensions='' c --header-only --loader
+ *
+ * Online:
+ *    http://glad.sh/#api=gl%3Acore%3D3.3&extensions=&generator=c&options=HEADER_ONLY%2CLOADER
+ *
+ */
+
+#ifndef GLAD_GL_H_
+#define GLAD_GL_H_
+
+#ifdef __clang__
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wreserved-id-macro"
+#endif
+#ifdef __gl_h_
+  #error OpenGL (gl.h) header already included (API: gl), remove previous include!
+#endif
+#define __gl_h_ 1
+#ifdef __gl3_h_
+  #error OpenGL (gl3.h) header already included (API: gl), remove previous include!
+#endif
+#define __gl3_h_ 1
+#ifdef __glext_h_
+  #error OpenGL (glext.h) header already included (API: gl), remove previous include!
+#endif
+#define __glext_h_ 1
+#ifdef __gl3ext_h_
+  #error OpenGL (gl3ext.h) header already included (API: gl), remove previous include!
+#endif
+#define __gl3ext_h_ 1
+#ifdef __clang__
+#pragma clang diagnostic pop
+#endif
+
+#define GLAD_GL
+#define GLAD_OPTION_GL_HEADER_ONLY
+#define GLAD_OPTION_GL_LOADER
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef GLAD_PLATFORM_H_
+#define GLAD_PLATFORM_H_
+
+#ifndef GLAD_PLATFORM_WIN32
+  #if defined(_WIN32) || defined(__WIN32__) || defined(WIN32) || defined(__MINGW32__)
+    #define GLAD_PLATFORM_WIN32 1
+  #else
+    #define GLAD_PLATFORM_WIN32 0
+  #endif
+#endif
+
+#ifndef GLAD_PLATFORM_APPLE
+  #ifdef __APPLE__
+    #define GLAD_PLATFORM_APPLE 1
+  #else
+    #define GLAD_PLATFORM_APPLE 0
+  #endif
+#endif
+
+#ifndef GLAD_PLATFORM_EMSCRIPTEN
+  #ifdef __EMSCRIPTEN__
+    #define GLAD_PLATFORM_EMSCRIPTEN 1
+  #else
+    #define GLAD_PLATFORM_EMSCRIPTEN 0
+  #endif
+#endif
+
+#ifndef GLAD_PLATFORM_UWP
+  #if defined(_MSC_VER) && !defined(GLAD_INTERNAL_HAVE_WINAPIFAMILY)
+    #ifdef __has_include
+      #if __has_include(<winapifamily.h>)
+        #define GLAD_INTERNAL_HAVE_WINAPIFAMILY 1
+      #endif
+    #elif _MSC_VER >= 1700 && !_USING_V110_SDK71_
+      #define GLAD_INTERNAL_HAVE_WINAPIFAMILY 1
+    #endif
+  #endif
+
+  #ifdef GLAD_INTERNAL_HAVE_WINAPIFAMILY
+    #include <winapifamily.h>
+    #if !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) && WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP)
+      #define GLAD_PLATFORM_UWP 1
+    #endif
+  #endif
+
+  #ifndef GLAD_PLATFORM_UWP
+    #define GLAD_PLATFORM_UWP 0
+  #endif
+#endif
+
+#ifdef __GNUC__
+  #define GLAD_GNUC_EXTENSION __extension__
+#else
+  #define GLAD_GNUC_EXTENSION
+#endif
+
+#ifndef GLAD_API_CALL
+  #if defined(GLAD_API_CALL_EXPORT)
+    #if GLAD_PLATFORM_WIN32 || defined(__CYGWIN__)
+      #if defined(GLAD_API_CALL_EXPORT_BUILD)
+        #if defined(__GNUC__)
+          #define GLAD_API_CALL __attribute__ ((dllexport)) extern
+        #else
+          #define GLAD_API_CALL __declspec(dllexport) extern
+        #endif
+      #else
+        #if defined(__GNUC__)
+          #define GLAD_API_CALL __attribute__ ((dllimport)) extern
+        #else
+          #define GLAD_API_CALL __declspec(dllimport) extern
+        #endif
+      #endif
+    #elif defined(__GNUC__) && defined(GLAD_API_CALL_EXPORT_BUILD)
+      #define GLAD_API_CALL __attribute__ ((visibility ("default"))) extern
+    #else
+      #define GLAD_API_CALL extern
+    #endif
+  #else
+    #define GLAD_API_CALL extern
+  #endif
+#endif
+
+#ifdef APIENTRY
+  #define GLAD_API_PTR APIENTRY
+#elif GLAD_PLATFORM_WIN32
+  #define GLAD_API_PTR __stdcall
+#else
+  #define GLAD_API_PTR
+#endif
+
+#ifndef GLAPI
+#define GLAPI GLAD_API_CALL
+#endif
+
+#ifndef GLAPIENTRY
+#define GLAPIENTRY GLAD_API_PTR
+#endif
+
+#define GLAD_MAKE_VERSION(major, minor) (major * 10000 + minor)
+#define GLAD_VERSION_MAJOR(version) (version / 10000)
+#define GLAD_VERSION_MINOR(version) (version % 10000)
+
+#define GLAD_GENERATOR_VERSION "2.0.0-beta"
+
+typedef void (*GLADapiproc)(void);
+
+typedef GLADapiproc (*GLADloadfunc)(const char *name);
+typedef GLADapiproc (*GLADuserptrloadfunc)(void *userptr, const char *name);
+
+typedef void (*GLADprecallback)(const char *name, GLADapiproc apiproc, int len_args, ...);
+typedef void (*GLADpostcallback)(void *ret, const char *name, GLADapiproc apiproc, int len_args, ...);
+
+#endif /* GLAD_PLATFORM_H_ */
+
+#define GL_ACTIVE_ATTRIBUTES 0x8B89
+#define GL_ACTIVE_ATTRIBUTE_MAX_LENGTH 0x8B8A
+#define GL_ACTIVE_TEXTURE 0x84E0
+#define GL_ACTIVE_UNIFORMS 0x8B86
+#define GL_ACTIVE_UNIFORM_BLOCKS 0x8A36
+#define GL_ACTIVE_UNIFORM_BLOCK_MAX_NAME_LENGTH 0x8A35
+#define GL_ACTIVE_UNIFORM_MAX_LENGTH 0x8B87
+#define GL_ALIASED_LINE_WIDTH_RANGE 0x846E
+#define GL_ALPHA 0x1906
+#define GL_ALREADY_SIGNALED 0x911A
+#define GL_ALWAYS 0x0207
+#define GL_AND 0x1501
+#define GL_AND_INVERTED 0x1504
+#define GL_AND_REVERSE 0x1502
+#define GL_ANY_SAMPLES_PASSED 0x8C2F
+#define GL_ARRAY_BUFFER 0x8892
+#define GL_ARRAY_BUFFER_BINDING 0x8894
+#define GL_ATTACHED_SHADERS 0x8B85
+#define GL_BACK 0x0405
+#define GL_BACK_LEFT 0x0402
+#define GL_BACK_RIGHT 0x0403
+#define GL_BGR 0x80E0
+#define GL_BGRA 0x80E1
+#define GL_BGRA_INTEGER 0x8D9B
+#define GL_BGR_INTEGER 0x8D9A
+#define GL_BLEND 0x0BE2
+#define GL_BLEND_COLOR 0x8005
+#define GL_BLEND_DST 0x0BE0
+#define GL_BLEND_DST_ALPHA 0x80CA
+#define GL_BLEND_DST_RGB 0x80C8
+#define GL_BLEND_EQUATION 0x8009
+#define GL_BLEND_EQUATION_ALPHA 0x883D
+#define GL_BLEND_EQUATION_RGB 0x8009
+#define GL_BLEND_SRC 0x0BE1
+#define GL_BLEND_SRC_ALPHA 0x80CB
+#define GL_BLEND_SRC_RGB 0x80C9
+#define GL_BLUE 0x1905
+#define GL_BLUE_INTEGER 0x8D96
+#define GL_BOOL 0x8B56
+#define GL_BOOL_VEC2 0x8B57
+#define GL_BOOL_VEC3 0x8B58
+#define GL_BOOL_VEC4 0x8B59
+#define GL_BUFFER_ACCESS 0x88BB
+#define GL_BUFFER_ACCESS_FLAGS 0x911F
+#define GL_BUFFER_MAPPED 0x88BC
+#define GL_BUFFER_MAP_LENGTH 0x9120
+#define GL_BUFFER_MAP_OFFSET 0x9121
+#define GL_BUFFER_MAP_POINTER 0x88BD
+#define GL_BUFFER_SIZE 0x8764
+#define GL_BUFFER_USAGE 0x8765
+#define GL_BYTE 0x1400
+#define GL_CCW 0x0901
+#define GL_CLAMP_READ_COLOR 0x891C
+#define GL_CLAMP_TO_BORDER 0x812D
+#define GL_CLAMP_TO_EDGE 0x812F
+#define GL_CLEAR 0x1500
+#define GL_CLIP_DISTANCE0 0x3000
+#define GL_CLIP_DISTANCE1 0x3001
+#define GL_CLIP_DISTANCE2 0x3002
+#define GL_CLIP_DISTANCE3 0x3003
+#define GL_CLIP_DISTANCE4 0x3004
+#define GL_CLIP_DISTANCE5 0x3005
+#define GL_CLIP_DISTANCE6 0x3006
+#define GL_CLIP_DISTANCE7 0x3007
+#define GL_COLOR 0x1800
+#define GL_COLOR_ATTACHMENT0 0x8CE0
+#define GL_COLOR_ATTACHMENT1 0x8CE1
+#define GL_COLOR_ATTACHMENT10 0x8CEA
+#define GL_COLOR_ATTACHMENT11 0x8CEB
+#define GL_COLOR_ATTACHMENT12 0x8CEC
+#define GL_COLOR_ATTACHMENT13 0x8CED
+#define GL_COLOR_ATTACHMENT14 0x8CEE
+#define GL_COLOR_ATTACHMENT15 0x8CEF
+#define GL_COLOR_ATTACHMENT16 0x8CF0
+#define GL_COLOR_ATTACHMENT17 0x8CF1
+#define GL_COLOR_ATTACHMENT18 0x8CF2
+#define GL_COLOR_ATTACHMENT19 0x8CF3
+#define GL_COLOR_ATTACHMENT2 0x8CE2
+#define GL_COLOR_ATTACHMENT20 0x8CF4
+#define GL_COLOR_ATTACHMENT21 0x8CF5
+#define GL_COLOR_ATTACHMENT22 0x8CF6
+#define GL_COLOR_ATTACHMENT23 0x8CF7
+#define GL_COLOR_ATTACHMENT24 0x8CF8
+#define GL_COLOR_ATTACHMENT25 0x8CF9
+#define GL_COLOR_ATTACHMENT26 0x8CFA
+#define GL_COLOR_ATTACHMENT27 0x8CFB
+#define GL_COLOR_ATTACHMENT28 0x8CFC
+#define GL_COLOR_ATTACHMENT29 0x8CFD
+#define GL_COLOR_ATTACHMENT3 0x8CE3
+#define GL_COLOR_ATTACHMENT30 0x8CFE
+#define GL_COLOR_ATTACHMENT31 0x8CFF
+#define GL_COLOR_ATTACHMENT4 0x8CE4
+#define GL_COLOR_ATTACHMENT5 0x8CE5
+#define GL_COLOR_ATTACHMENT6 0x8CE6
+#define GL_COLOR_ATTACHMENT7 0x8CE7
+#define GL_COLOR_ATTACHMENT8 0x8CE8
+#define GL_COLOR_ATTACHMENT9 0x8CE9
+#define GL_COLOR_BUFFER_BIT 0x00004000
+#define GL_COLOR_CLEAR_VALUE 0x0C22
+#define GL_COLOR_LOGIC_OP 0x0BF2
+#define GL_COLOR_WRITEMASK 0x0C23
+#define GL_COMPARE_REF_TO_TEXTURE 0x884E
+#define GL_COMPILE_STATUS 0x8B81
+#define GL_COMPRESSED_RED 0x8225
+#define GL_COMPRESSED_RED_RGTC1 0x8DBB
+#define GL_COMPRESSED_RG 0x8226
+#define GL_COMPRESSED_RGB 0x84ED
+#define GL_COMPRESSED_RGBA 0x84EE
+#define GL_COMPRESSED_RG_RGTC2 0x8DBD
+#define GL_COMPRESSED_SIGNED_RED_RGTC1 0x8DBC
+#define GL_COMPRESSED_SIGNED_RG_RGTC2 0x8DBE
+#define GL_COMPRESSED_SRGB 0x8C48
+#define GL_COMPRESSED_SRGB_ALPHA 0x8C49
+#define GL_COMPRESSED_TEXTURE_FORMATS 0x86A3
+#define GL_CONDITION_SATISFIED 0x911C
+#define GL_CONSTANT_ALPHA 0x8003
+#define GL_CONSTANT_COLOR 0x8001
+#define GL_CONTEXT_COMPATIBILITY_PROFILE_BIT 0x00000002
+#define GL_CONTEXT_CORE_PROFILE_BIT 0x00000001
+#define GL_CONTEXT_FLAGS 0x821E
+#define GL_CONTEXT_FLAG_FORWARD_COMPATIBLE_BIT 0x00000001
+#define GL_CONTEXT_PROFILE_MASK 0x9126
+#define GL_COPY 0x1503
+#define GL_COPY_INVERTED 0x150C
+#define GL_COPY_READ_BUFFER 0x8F36
+#define GL_COPY_WRITE_BUFFER 0x8F37
+#define GL_CULL_FACE 0x0B44
+#define GL_CULL_FACE_MODE 0x0B45
+#define GL_CURRENT_PROGRAM 0x8B8D
+#define GL_CURRENT_QUERY 0x8865
+#define GL_CURRENT_VERTEX_ATTRIB 0x8626
+#define GL_CW 0x0900
+#define GL_DECR 0x1E03
+#define GL_DECR_WRAP 0x8508
+#define GL_DELETE_STATUS 0x8B80
+#define GL_DEPTH 0x1801
+#define GL_DEPTH24_STENCIL8 0x88F0
+#define GL_DEPTH32F_STENCIL8 0x8CAD
+#define GL_DEPTH_ATTACHMENT 0x8D00
+#define GL_DEPTH_BUFFER_BIT 0x00000100
+#define GL_DEPTH_CLAMP 0x864F
+#define GL_DEPTH_CLEAR_VALUE 0x0B73
+#define GL_DEPTH_COMPONENT 0x1902
+#define GL_DEPTH_COMPONENT16 0x81A5
+#define GL_DEPTH_COMPONENT24 0x81A6
+#define GL_DEPTH_COMPONENT32 0x81A7
+#define GL_DEPTH_COMPONENT32F 0x8CAC
+#define GL_DEPTH_FUNC 0x0B74
+#define GL_DEPTH_RANGE 0x0B70
+#define GL_DEPTH_STENCIL 0x84F9
+#define GL_DEPTH_STENCIL_ATTACHMENT 0x821A
+#define GL_DEPTH_TEST 0x0B71
+#define GL_DEPTH_WRITEMASK 0x0B72
+#define GL_DITHER 0x0BD0
+#define GL_DONT_CARE 0x1100
+#define GL_DOUBLE 0x140A
+#define GL_DOUBLEBUFFER 0x0C32
+#define GL_DRAW_BUFFER 0x0C01
+#define GL_DRAW_BUFFER0 0x8825
+#define GL_DRAW_BUFFER1 0x8826
+#define GL_DRAW_BUFFER10 0x882F
+#define GL_DRAW_BUFFER11 0x8830
+#define GL_DRAW_BUFFER12 0x8831
+#define GL_DRAW_BUFFER13 0x8832
+#define GL_DRAW_BUFFER14 0x8833
+#define GL_DRAW_BUFFER15 0x8834
+#define GL_DRAW_BUFFER2 0x8827
+#define GL_DRAW_BUFFER3 0x8828
+#define GL_DRAW_BUFFER4 0x8829
+#define GL_DRAW_BUFFER5 0x882A
+#define GL_DRAW_BUFFER6 0x882B
+#define GL_DRAW_BUFFER7 0x882C
+#define GL_DRAW_BUFFER8 0x882D
+#define GL_DRAW_BUFFER9 0x882E
+#define GL_DRAW_FRAMEBUFFER 0x8CA9
+#define GL_DRAW_FRAMEBUFFER_BINDING 0x8CA6
+#define GL_DST_ALPHA 0x0304
+#define GL_DST_COLOR 0x0306
+#define GL_DYNAMIC_COPY 0x88EA
+#define GL_DYNAMIC_DRAW 0x88E8
+#define GL_DYNAMIC_READ 0x88E9
+#define GL_ELEMENT_ARRAY_BUFFER 0x8893
+#define GL_ELEMENT_ARRAY_BUFFER_BINDING 0x8895
+#define GL_EQUAL 0x0202
+#define GL_EQUIV 0x1509
+#define GL_EXTENSIONS 0x1F03
+#define GL_FALSE 0
+#define GL_FASTEST 0x1101
+#define GL_FILL 0x1B02
+#define GL_FIRST_VERTEX_CONVENTION 0x8E4D
+#define GL_FIXED_ONLY 0x891D
+#define GL_FLOAT 0x1406
+#define GL_FLOAT_32_UNSIGNED_INT_24_8_REV 0x8DAD
+#define GL_FLOAT_MAT2 0x8B5A
+#define GL_FLOAT_MAT2x3 0x8B65
+#define GL_FLOAT_MAT2x4 0x8B66
+#define GL_FLOAT_MAT3 0x8B5B
+#define GL_FLOAT_MAT3x2 0x8B67
+#define GL_FLOAT_MAT3x4 0x8B68
+#define GL_FLOAT_MAT4 0x8B5C
+#define GL_FLOAT_MAT4x2 0x8B69
+#define GL_FLOAT_MAT4x3 0x8B6A
+#define GL_FLOAT_VEC2 0x8B50
+#define GL_FLOAT_VEC3 0x8B51
+#define GL_FLOAT_VEC4 0x8B52
+#define GL_FRAGMENT_SHADER 0x8B30
+#define GL_FRAGMENT_SHADER_DERIVATIVE_HINT 0x8B8B
+#define GL_FRAMEBUFFER 0x8D40
+#define GL_FRAMEBUFFER_ATTACHMENT_ALPHA_SIZE 0x8215
+#define GL_FRAMEBUFFER_ATTACHMENT_BLUE_SIZE 0x8214
+#define GL_FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING 0x8210
+#define GL_FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE 0x8211
+#define GL_FRAMEBUFFER_ATTACHMENT_DEPTH_SIZE 0x8216
+#define GL_FRAMEBUFFER_ATTACHMENT_GREEN_SIZE 0x8213
+#define GL_FRAMEBUFFER_ATTACHMENT_LAYERED 0x8DA7
+#define GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME 0x8CD1
+#define GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE 0x8CD0
+#define GL_FRAMEBUFFER_ATTACHMENT_RED_SIZE 0x8212
+#define GL_FRAMEBUFFER_ATTACHMENT_STENCIL_SIZE 0x8217
+#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE 0x8CD3
+#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LAYER 0x8CD4
+#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL 0x8CD2
+#define GL_FRAMEBUFFER_BINDING 0x8CA6
+#define GL_FRAMEBUFFER_COMPLETE 0x8CD5
+#define GL_FRAMEBUFFER_DEFAULT 0x8218
+#define GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT 0x8CD6
+#define GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER 0x8CDB
+#define GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS 0x8DA8
+#define GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT 0x8CD7
+#define GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE 0x8D56
+#define GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER 0x8CDC
+#define GL_FRAMEBUFFER_SRGB 0x8DB9
+#define GL_FRAMEBUFFER_UNDEFINED 0x8219
+#define GL_FRAMEBUFFER_UNSUPPORTED 0x8CDD
+#define GL_FRONT 0x0404
+#define GL_FRONT_AND_BACK 0x0408
+#define GL_FRONT_FACE 0x0B46
+#define GL_FRONT_LEFT 0x0400
+#define GL_FRONT_RIGHT 0x0401
+#define GL_FUNC_ADD 0x8006
+#define GL_FUNC_REVERSE_SUBTRACT 0x800B
+#define GL_FUNC_SUBTRACT 0x800A
+#define GL_GEOMETRY_INPUT_TYPE 0x8917
+#define GL_GEOMETRY_OUTPUT_TYPE 0x8918
+#define GL_GEOMETRY_SHADER 0x8DD9
+#define GL_GEOMETRY_VERTICES_OUT 0x8916
+#define GL_GEQUAL 0x0206
+#define GL_GREATER 0x0204
+#define GL_GREEN 0x1904
+#define GL_GREEN_INTEGER 0x8D95
+#define GL_HALF_FLOAT 0x140B
+#define GL_INCR 0x1E02
+#define GL_INCR_WRAP 0x8507
+#define GL_INFO_LOG_LENGTH 0x8B84
+#define GL_INT 0x1404
+#define GL_INTERLEAVED_ATTRIBS 0x8C8C
+#define GL_INT_2_10_10_10_REV 0x8D9F
+#define GL_INT_SAMPLER_1D 0x8DC9
+#define GL_INT_SAMPLER_1D_ARRAY 0x8DCE
+#define GL_INT_SAMPLER_2D 0x8DCA
+#define GL_INT_SAMPLER_2D_ARRAY 0x8DCF
+#define GL_INT_SAMPLER_2D_MULTISAMPLE 0x9109
+#define GL_INT_SAMPLER_2D_MULTISAMPLE_ARRAY 0x910C
+#define GL_INT_SAMPLER_2D_RECT 0x8DCD
+#define GL_INT_SAMPLER_3D 0x8DCB
+#define GL_INT_SAMPLER_BUFFER 0x8DD0
+#define GL_INT_SAMPLER_CUBE 0x8DCC
+#define GL_INT_VEC2 0x8B53
+#define GL_INT_VEC3 0x8B54
+#define GL_INT_VEC4 0x8B55
+#define GL_INVALID_ENUM 0x0500
+#define GL_INVALID_FRAMEBUFFER_OPERATION 0x0506
+#define GL_INVALID_INDEX 0xFFFFFFFF
+#define GL_INVALID_OPERATION 0x0502
+#define GL_INVALID_VALUE 0x0501
+#define GL_INVERT 0x150A
+#define GL_KEEP 0x1E00
+#define GL_LAST_VERTEX_CONVENTION 0x8E4E
+#define GL_LEFT 0x0406
+#define GL_LEQUAL 0x0203
+#define GL_LESS 0x0201
+#define GL_LINE 0x1B01
+#define GL_LINEAR 0x2601
+#define GL_LINEAR_MIPMAP_LINEAR 0x2703
+#define GL_LINEAR_MIPMAP_NEAREST 0x2701
+#define GL_LINES 0x0001
+#define GL_LINES_ADJACENCY 0x000A
+#define GL_LINE_LOOP 0x0002
+#define GL_LINE_SMOOTH 0x0B20
+#define GL_LINE_SMOOTH_HINT 0x0C52
+#define GL_LINE_STRIP 0x0003
+#define GL_LINE_STRIP_ADJACENCY 0x000B
+#define GL_LINE_WIDTH 0x0B21
+#define GL_LINE_WIDTH_GRANULARITY 0x0B23
+#define GL_LINE_WIDTH_RANGE 0x0B22
+#define GL_LINK_STATUS 0x8B82
+#define GL_LOGIC_OP_MODE 0x0BF0
+#define GL_LOWER_LEFT 0x8CA1
+#define GL_MAJOR_VERSION 0x821B
+#define GL_MAP_FLUSH_EXPLICIT_BIT 0x0010
+#define GL_MAP_INVALIDATE_BUFFER_BIT 0x0008
+#define GL_MAP_INVALIDATE_RANGE_BIT 0x0004
+#define GL_MAP_READ_BIT 0x0001
+#define GL_MAP_UNSYNCHRONIZED_BIT 0x0020
+#define GL_MAP_WRITE_BIT 0x0002
+#define GL_MAX 0x8008
+#define GL_MAX_3D_TEXTURE_SIZE 0x8073
+#define GL_MAX_ARRAY_TEXTURE_LAYERS 0x88FF
+#define GL_MAX_CLIP_DISTANCES 0x0D32
+#define GL_MAX_COLOR_ATTACHMENTS 0x8CDF
+#define GL_MAX_COLOR_TEXTURE_SAMPLES 0x910E
+#define GL_MAX_COMBINED_FRAGMENT_UNIFORM_COMPONENTS 0x8A33
+#define GL_MAX_COMBINED_GEOMETRY_UNIFORM_COMPONENTS 0x8A32
+#define GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS 0x8B4D
+#define GL_MAX_COMBINED_UNIFORM_BLOCKS 0x8A2E
+#define GL_MAX_COMBINED_VERTEX_UNIFORM_COMPONENTS 0x8A31
+#define GL_MAX_CUBE_MAP_TEXTURE_SIZE 0x851C
+#define GL_MAX_DEPTH_TEXTURE_SAMPLES 0x910F
+#define GL_MAX_DRAW_BUFFERS 0x8824
+#define GL_MAX_DUAL_SOURCE_DRAW_BUFFERS 0x88FC
+#define GL_MAX_ELEMENTS_INDICES 0x80E9
+#define GL_MAX_ELEMENTS_VERTICES 0x80E8
+#define GL_MAX_FRAGMENT_INPUT_COMPONENTS 0x9125
+#define GL_MAX_FRAGMENT_UNIFORM_BLOCKS 0x8A2D
+#define GL_MAX_FRAGMENT_UNIFORM_COMPONENTS 0x8B49
+#define GL_MAX_GEOMETRY_INPUT_COMPONENTS 0x9123
+#define GL_MAX_GEOMETRY_OUTPUT_COMPONENTS 0x9124
+#define GL_MAX_GEOMETRY_OUTPUT_VERTICES 0x8DE0
+#define GL_MAX_GEOMETRY_TEXTURE_IMAGE_UNITS 0x8C29
+#define GL_MAX_GEOMETRY_TOTAL_OUTPUT_COMPONENTS 0x8DE1
+#define GL_MAX_GEOMETRY_UNIFORM_BLOCKS 0x8A2C
+#define GL_MAX_GEOMETRY_UNIFORM_COMPONENTS 0x8DDF
+#define GL_MAX_INTEGER_SAMPLES 0x9110
+#define GL_MAX_PROGRAM_TEXEL_OFFSET 0x8905
+#define GL_MAX_RECTANGLE_TEXTURE_SIZE 0x84F8
+#define GL_MAX_RENDERBUFFER_SIZE 0x84E8
+#define GL_MAX_SAMPLES 0x8D57
+#define GL_MAX_SAMPLE_MASK_WORDS 0x8E59
+#define GL_MAX_SERVER_WAIT_TIMEOUT 0x9111
+#define GL_MAX_TEXTURE_BUFFER_SIZE 0x8C2B
+#define GL_MAX_TEXTURE_IMAGE_UNITS 0x8872
+#define GL_MAX_TEXTURE_LOD_BIAS 0x84FD
+#define GL_MAX_TEXTURE_SIZE 0x0D33
+#define GL_MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS 0x8C8A
+#define GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS 0x8C8B
+#define GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_COMPONENTS 0x8C80
+#define GL_MAX_UNIFORM_BLOCK_SIZE 0x8A30
+#define GL_MAX_UNIFORM_BUFFER_BINDINGS 0x8A2F
+#define GL_MAX_VARYING_COMPONENTS 0x8B4B
+#define GL_MAX_VARYING_FLOATS 0x8B4B
+#define GL_MAX_VERTEX_ATTRIBS 0x8869
+#define GL_MAX_VERTEX_OUTPUT_COMPONENTS 0x9122
+#define GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS 0x8B4C
+#define GL_MAX_VERTEX_UNIFORM_BLOCKS 0x8A2B
+#define GL_MAX_VERTEX_UNIFORM_COMPONENTS 0x8B4A
+#define GL_MAX_VIEWPORT_DIMS 0x0D3A
+#define GL_MIN 0x8007
+#define GL_MINOR_VERSION 0x821C
+#define GL_MIN_PROGRAM_TEXEL_OFFSET 0x8904
+#define GL_MIRRORED_REPEAT 0x8370
+#define GL_MULTISAMPLE 0x809D
+#define GL_NAND 0x150E
+#define GL_NEAREST 0x2600
+#define GL_NEAREST_MIPMAP_LINEAR 0x2702
+#define GL_NEAREST_MIPMAP_NEAREST 0x2700
+#define GL_NEVER 0x0200
+#define GL_NICEST 0x1102
+#define GL_NONE 0
+#define GL_NOOP 0x1505
+#define GL_NOR 0x1508
+#define GL_NOTEQUAL 0x0205
+#define GL_NO_ERROR 0
+#define GL_NUM_COMPRESSED_TEXTURE_FORMATS 0x86A2
+#define GL_NUM_EXTENSIONS 0x821D
+#define GL_OBJECT_TYPE 0x9112
+#define GL_ONE 1
+#define GL_ONE_MINUS_CONSTANT_ALPHA 0x8004
+#define GL_ONE_MINUS_CONSTANT_COLOR 0x8002
+#define GL_ONE_MINUS_DST_ALPHA 0x0305
+#define GL_ONE_MINUS_DST_COLOR 0x0307
+#define GL_ONE_MINUS_SRC1_ALPHA 0x88FB
+#define GL_ONE_MINUS_SRC1_COLOR 0x88FA
+#define GL_ONE_MINUS_SRC_ALPHA 0x0303
+#define GL_ONE_MINUS_SRC_COLOR 0x0301
+#define GL_OR 0x1507
+#define GL_OR_INVERTED 0x150D
+#define GL_OR_REVERSE 0x150B
+#define GL_OUT_OF_MEMORY 0x0505
+#define GL_PACK_ALIGNMENT 0x0D05
+#define GL_PACK_IMAGE_HEIGHT 0x806C
+#define GL_PACK_LSB_FIRST 0x0D01
+#define GL_PACK_ROW_LENGTH 0x0D02
+#define GL_PACK_SKIP_IMAGES 0x806B
+#define GL_PACK_SKIP_PIXELS 0x0D04
+#define GL_PACK_SKIP_ROWS 0x0D03
+#define GL_PACK_SWAP_BYTES 0x0D00
+#define GL_PIXEL_PACK_BUFFER 0x88EB
+#define GL_PIXEL_PACK_BUFFER_BINDING 0x88ED
+#define GL_PIXEL_UNPACK_BUFFER 0x88EC
+#define GL_PIXEL_UNPACK_BUFFER_BINDING 0x88EF
+#define GL_POINT 0x1B00
+#define GL_POINTS 0x0000
+#define GL_POINT_FADE_THRESHOLD_SIZE 0x8128
+#define GL_POINT_SIZE 0x0B11
+#define GL_POINT_SIZE_GRANULARITY 0x0B13
+#define GL_POINT_SIZE_RANGE 0x0B12
+#define GL_POINT_SPRITE_COORD_ORIGIN 0x8CA0
+#define GL_POLYGON_MODE 0x0B40
+#define GL_POLYGON_OFFSET_FACTOR 0x8038
+#define GL_POLYGON_OFFSET_FILL 0x8037
+#define GL_POLYGON_OFFSET_LINE 0x2A02
+#define GL_POLYGON_OFFSET_POINT 0x2A01
+#define GL_POLYGON_OFFSET_UNITS 0x2A00
+#define GL_POLYGON_SMOOTH 0x0B41
+#define GL_POLYGON_SMOOTH_HINT 0x0C53
+#define GL_PRIMITIVES_GENERATED 0x8C87
+#define GL_PRIMITIVE_RESTART 0x8F9D
+#define GL_PRIMITIVE_RESTART_INDEX 0x8F9E
+#define GL_PROGRAM_POINT_SIZE 0x8642
+#define GL_PROVOKING_VERTEX 0x8E4F
+#define GL_PROXY_TEXTURE_1D 0x8063
+#define GL_PROXY_TEXTURE_1D_ARRAY 0x8C19
+#define GL_PROXY_TEXTURE_2D 0x8064
+#define GL_PROXY_TEXTURE_2D_ARRAY 0x8C1B
+#define GL_PROXY_TEXTURE_2D_MULTISAMPLE 0x9101
+#define GL_PROXY_TEXTURE_2D_MULTISAMPLE_ARRAY 0x9103
+#define GL_PROXY_TEXTURE_3D 0x8070
+#define GL_PROXY_TEXTURE_CUBE_MAP 0x851B
+#define GL_PROXY_TEXTURE_RECTANGLE 0x84F7
+#define GL_QUADS_FOLLOW_PROVOKING_VERTEX_CONVENTION 0x8E4C
+#define GL_QUERY_BY_REGION_NO_WAIT 0x8E16
+#define GL_QUERY_BY_REGION_WAIT 0x8E15
+#define GL_QUERY_COUNTER_BITS 0x8864
+#define GL_QUERY_NO_WAIT 0x8E14
+#define GL_QUERY_RESULT 0x8866
+#define GL_QUERY_RESULT_AVAILABLE 0x8867
+#define GL_QUERY_WAIT 0x8E13
+#define GL_R11F_G11F_B10F 0x8C3A
+#define GL_R16 0x822A
+#define GL_R16F 0x822D
+#define GL_R16I 0x8233
+#define GL_R16UI 0x8234
+#define GL_R16_SNORM 0x8F98
+#define GL_R32F 0x822E
+#define GL_R32I 0x8235
+#define GL_R32UI 0x8236
+#define GL_R3_G3_B2 0x2A10
+#define GL_R8 0x8229
+#define GL_R8I 0x8231
+#define GL_R8UI 0x8232
+#define GL_R8_SNORM 0x8F94
+#define GL_RASTERIZER_DISCARD 0x8C89
+#define GL_READ_BUFFER 0x0C02
+#define GL_READ_FRAMEBUFFER 0x8CA8
+#define GL_READ_FRAMEBUFFER_BINDING 0x8CAA
+#define GL_READ_ONLY 0x88B8
+#define GL_READ_WRITE 0x88BA
+#define GL_RED 0x1903
+#define GL_RED_INTEGER 0x8D94
+#define GL_RENDERBUFFER 0x8D41
+#define GL_RENDERBUFFER_ALPHA_SIZE 0x8D53
+#define GL_RENDERBUFFER_BINDING 0x8CA7
+#define GL_RENDERBUFFER_BLUE_SIZE 0x8D52
+#define GL_RENDERBUFFER_DEPTH_SIZE 0x8D54
+#define GL_RENDERBUFFER_GREEN_SIZE 0x8D51
+#define GL_RENDERBUFFER_HEIGHT 0x8D43
+#define GL_RENDERBUFFER_INTERNAL_FORMAT 0x8D44
+#define GL_RENDERBUFFER_RED_SIZE 0x8D50
+#define GL_RENDERBUFFER_SAMPLES 0x8CAB
+#define GL_RENDERBUFFER_STENCIL_SIZE 0x8D55
+#define GL_RENDERBUFFER_WIDTH 0x8D42
+#define GL_RENDERER 0x1F01
+#define GL_REPEAT 0x2901
+#define GL_REPLACE 0x1E01
+#define GL_RG 0x8227
+#define GL_RG16 0x822C
+#define GL_RG16F 0x822F
+#define GL_RG16I 0x8239
+#define GL_RG16UI 0x823A
+#define GL_RG16_SNORM 0x8F99
+#define GL_RG32F 0x8230
+#define GL_RG32I 0x823B
+#define GL_RG32UI 0x823C
+#define GL_RG8 0x822B
+#define GL_RG8I 0x8237
+#define GL_RG8UI 0x8238
+#define GL_RG8_SNORM 0x8F95
+#define GL_RGB 0x1907
+#define GL_RGB10 0x8052
+#define GL_RGB10_A2 0x8059
+#define GL_RGB10_A2UI 0x906F
+#define GL_RGB12 0x8053
+#define GL_RGB16 0x8054
+#define GL_RGB16F 0x881B
+#define GL_RGB16I 0x8D89
+#define GL_RGB16UI 0x8D77
+#define GL_RGB16_SNORM 0x8F9A
+#define GL_RGB32F 0x8815
+#define GL_RGB32I 0x8D83
+#define GL_RGB32UI 0x8D71
+#define GL_RGB4 0x804F
+#define GL_RGB5 0x8050
+#define GL_RGB5_A1 0x8057
+#define GL_RGB8 0x8051
+#define GL_RGB8I 0x8D8F
+#define GL_RGB8UI 0x8D7D
+#define GL_RGB8_SNORM 0x8F96
+#define GL_RGB9_E5 0x8C3D
+#define GL_RGBA 0x1908
+#define GL_RGBA12 0x805A
+#define GL_RGBA16 0x805B
+#define GL_RGBA16F 0x881A
+#define GL_RGBA16I 0x8D88
+#define GL_RGBA16UI 0x8D76
+#define GL_RGBA16_SNORM 0x8F9B
+#define GL_RGBA2 0x8055
+#define GL_RGBA32F 0x8814
+#define GL_RGBA32I 0x8D82
+#define GL_RGBA32UI 0x8D70
+#define GL_RGBA4 0x8056
+#define GL_RGBA8 0x8058
+#define GL_RGBA8I 0x8D8E
+#define GL_RGBA8UI 0x8D7C
+#define GL_RGBA8_SNORM 0x8F97
+#define GL_RGBA_INTEGER 0x8D99
+#define GL_RGB_INTEGER 0x8D98
+#define GL_RG_INTEGER 0x8228
+#define GL_RIGHT 0x0407
+#define GL_SAMPLER_1D 0x8B5D
+#define GL_SAMPLER_1D_ARRAY 0x8DC0
+#define GL_SAMPLER_1D_ARRAY_SHADOW 0x8DC3
+#define GL_SAMPLER_1D_SHADOW 0x8B61
+#define GL_SAMPLER_2D 0x8B5E
+#define GL_SAMPLER_2D_ARRAY 0x8DC1
+#define GL_SAMPLER_2D_ARRAY_SHADOW 0x8DC4
+#define GL_SAMPLER_2D_MULTISAMPLE 0x9108
+#define GL_SAMPLER_2D_MULTISAMPLE_ARRAY 0x910B
+#define GL_SAMPLER_2D_RECT 0x8B63
+#define GL_SAMPLER_2D_RECT_SHADOW 0x8B64
+#define GL_SAMPLER_2D_SHADOW 0x8B62
+#define GL_SAMPLER_3D 0x8B5F
+#define GL_SAMPLER_BINDING 0x8919
+#define GL_SAMPLER_BUFFER 0x8DC2
+#define GL_SAMPLER_CUBE 0x8B60
+#define GL_SAMPLER_CUBE_SHADOW 0x8DC5
+#define GL_SAMPLES 0x80A9
+#define GL_SAMPLES_PASSED 0x8914
+#define GL_SAMPLE_ALPHA_TO_COVERAGE 0x809E
+#define GL_SAMPLE_ALPHA_TO_ONE 0x809F
+#define GL_SAMPLE_BUFFERS 0x80A8
+#define GL_SAMPLE_COVERAGE 0x80A0
+#define GL_SAMPLE_COVERAGE_INVERT 0x80AB
+#define GL_SAMPLE_COVERAGE_VALUE 0x80AA
+#define GL_SAMPLE_MASK 0x8E51
+#define GL_SAMPLE_MASK_VALUE 0x8E52
+#define GL_SAMPLE_POSITION 0x8E50
+#define GL_SCISSOR_BOX 0x0C10
+#define GL_SCISSOR_TEST 0x0C11
+#define GL_SEPARATE_ATTRIBS 0x8C8D
+#define GL_SET 0x150F
+#define GL_SHADER_SOURCE_LENGTH 0x8B88
+#define GL_SHADER_TYPE 0x8B4F
+#define GL_SHADING_LANGUAGE_VERSION 0x8B8C
+#define GL_SHORT 0x1402
+#define GL_SIGNALED 0x9119
+#define GL_SIGNED_NORMALIZED 0x8F9C
+#define GL_SMOOTH_LINE_WIDTH_GRANULARITY 0x0B23
+#define GL_SMOOTH_LINE_WIDTH_RANGE 0x0B22
+#define GL_SMOOTH_POINT_SIZE_GRANULARITY 0x0B13
+#define GL_SMOOTH_POINT_SIZE_RANGE 0x0B12
+#define GL_SRC1_ALPHA 0x8589
+#define GL_SRC1_COLOR 0x88F9
+#define GL_SRC_ALPHA 0x0302
+#define GL_SRC_ALPHA_SATURATE 0x0308
+#define GL_SRC_COLOR 0x0300
+#define GL_SRGB 0x8C40
+#define GL_SRGB8 0x8C41
+#define GL_SRGB8_ALPHA8 0x8C43
+#define GL_SRGB_ALPHA 0x8C42
+#define GL_STATIC_COPY 0x88E6
+#define GL_STATIC_DRAW 0x88E4
+#define GL_STATIC_READ 0x88E5
+#define GL_STENCIL 0x1802
+#define GL_STENCIL_ATTACHMENT 0x8D20
+#define GL_STENCIL_BACK_FAIL 0x8801
+#define GL_STENCIL_BACK_FUNC 0x8800
+#define GL_STENCIL_BACK_PASS_DEPTH_FAIL 0x8802
+#define GL_STENCIL_BACK_PASS_DEPTH_PASS 0x8803
+#define GL_STENCIL_BACK_REF 0x8CA3
+#define GL_STENCIL_BACK_VALUE_MASK 0x8CA4
+#define GL_STENCIL_BACK_WRITEMASK 0x8CA5
+#define GL_STENCIL_BUFFER_BIT 0x00000400
+#define GL_STENCIL_CLEAR_VALUE 0x0B91
+#define GL_STENCIL_FAIL 0x0B94
+#define GL_STENCIL_FUNC 0x0B92
+#define GL_STENCIL_INDEX 0x1901
+#define GL_STENCIL_INDEX1 0x8D46
+#define GL_STENCIL_INDEX16 0x8D49
+#define GL_STENCIL_INDEX4 0x8D47
+#define GL_STENCIL_INDEX8 0x8D48
+#define GL_STENCIL_PASS_DEPTH_FAIL 0x0B95
+#define GL_STENCIL_PASS_DEPTH_PASS 0x0B96
+#define GL_STENCIL_REF 0x0B97
+#define GL_STENCIL_TEST 0x0B90
+#define GL_STENCIL_VALUE_MASK 0x0B93
+#define GL_STENCIL_WRITEMASK 0x0B98
+#define GL_STEREO 0x0C33
+#define GL_STREAM_COPY 0x88E2
+#define GL_STREAM_DRAW 0x88E0
+#define GL_STREAM_READ 0x88E1
+#define GL_SUBPIXEL_BITS 0x0D50
+#define GL_SYNC_CONDITION 0x9113
+#define GL_SYNC_FENCE 0x9116
+#define GL_SYNC_FLAGS 0x9115
+#define GL_SYNC_FLUSH_COMMANDS_BIT 0x00000001
+#define GL_SYNC_GPU_COMMANDS_COMPLETE 0x9117
+#define GL_SYNC_STATUS 0x9114
+#define GL_TEXTURE 0x1702
+#define GL_TEXTURE0 0x84C0
+#define GL_TEXTURE1 0x84C1
+#define GL_TEXTURE10 0x84CA
+#define GL_TEXTURE11 0x84CB
+#define GL_TEXTURE12 0x84CC
+#define GL_TEXTURE13 0x84CD
+#define GL_TEXTURE14 0x84CE
+#define GL_TEXTURE15 0x84CF
+#define GL_TEXTURE16 0x84D0
+#define GL_TEXTURE17 0x84D1
+#define GL_TEXTURE18 0x84D2
+#define GL_TEXTURE19 0x84D3
+#define GL_TEXTURE2 0x84C2
+#define GL_TEXTURE20 0x84D4
+#define GL_TEXTURE21 0x84D5
+#define GL_TEXTURE22 0x84D6
+#define GL_TEXTURE23 0x84D7
+#define GL_TEXTURE24 0x84D8
+#define GL_TEXTURE25 0x84D9
+#define GL_TEXTURE26 0x84DA
+#define GL_TEXTURE27 0x84DB
+#define GL_TEXTURE28 0x84DC
+#define GL_TEXTURE29 0x84DD
+#define GL_TEXTURE3 0x84C3
+#define GL_TEXTURE30 0x84DE
+#define GL_TEXTURE31 0x84DF
+#define GL_TEXTURE4 0x84C4
+#define GL_TEXTURE5 0x84C5
+#define GL_TEXTURE6 0x84C6
+#define GL_TEXTURE7 0x84C7
+#define GL_TEXTURE8 0x84C8
+#define GL_TEXTURE9 0x84C9
+#define GL_TEXTURE_1D 0x0DE0
+#define GL_TEXTURE_1D_ARRAY 0x8C18
+#define GL_TEXTURE_2D 0x0DE1
+#define GL_TEXTURE_2D_ARRAY 0x8C1A
+#define GL_TEXTURE_2D_MULTISAMPLE 0x9100
+#define GL_TEXTURE_2D_MULTISAMPLE_ARRAY 0x9102
+#define GL_TEXTURE_3D 0x806F
+#define GL_TEXTURE_ALPHA_SIZE 0x805F
+#define GL_TEXTURE_ALPHA_TYPE 0x8C13
+#define GL_TEXTURE_BASE_LEVEL 0x813C
+#define GL_TEXTURE_BINDING_1D 0x8068
+#define GL_TEXTURE_BINDING_1D_ARRAY 0x8C1C
+#define GL_TEXTURE_BINDING_2D 0x8069
+#define GL_TEXTURE_BINDING_2D_ARRAY 0x8C1D
+#define GL_TEXTURE_BINDING_2D_MULTISAMPLE 0x9104
+#define GL_TEXTURE_BINDING_2D_MULTISAMPLE_ARRAY 0x9105
+#define GL_TEXTURE_BINDING_3D 0x806A
+#define GL_TEXTURE_BINDING_BUFFER 0x8C2C
+#define GL_TEXTURE_BINDING_CUBE_MAP 0x8514
+#define GL_TEXTURE_BINDING_RECTANGLE 0x84F6
+#define GL_TEXTURE_BLUE_SIZE 0x805E
+#define GL_TEXTURE_BLUE_TYPE 0x8C12
+#define GL_TEXTURE_BORDER_COLOR 0x1004
+#define GL_TEXTURE_BUFFER 0x8C2A
+#define GL_TEXTURE_BUFFER_DATA_STORE_BINDING 0x8C2D
+#define GL_TEXTURE_COMPARE_FUNC 0x884D
+#define GL_TEXTURE_COMPARE_MODE 0x884C
+#define GL_TEXTURE_COMPRESSED 0x86A1
+#define GL_TEXTURE_COMPRESSED_IMAGE_SIZE 0x86A0
+#define GL_TEXTURE_COMPRESSION_HINT 0x84EF
+#define GL_TEXTURE_CUBE_MAP 0x8513
+#define GL_TEXTURE_CUBE_MAP_NEGATIVE_X 0x8516
+#define GL_TEXTURE_CUBE_MAP_NEGATIVE_Y 0x8518
+#define GL_TEXTURE_CUBE_MAP_NEGATIVE_Z 0x851A
+#define GL_TEXTURE_CUBE_MAP_POSITIVE_X 0x8515
+#define GL_TEXTURE_CUBE_MAP_POSITIVE_Y 0x8517
+#define GL_TEXTURE_CUBE_MAP_POSITIVE_Z 0x8519
+#define GL_TEXTURE_CUBE_MAP_SEAMLESS 0x884F
+#define GL_TEXTURE_DEPTH 0x8071
+#define GL_TEXTURE_DEPTH_SIZE 0x884A
+#define GL_TEXTURE_DEPTH_TYPE 0x8C16
+#define GL_TEXTURE_FIXED_SAMPLE_LOCATIONS 0x9107
+#define GL_TEXTURE_GREEN_SIZE 0x805D
+#define GL_TEXTURE_GREEN_TYPE 0x8C11
+#define GL_TEXTURE_HEIGHT 0x1001
+#define GL_TEXTURE_INTERNAL_FORMAT 0x1003
+#define GL_TEXTURE_LOD_BIAS 0x8501
+#define GL_TEXTURE_MAG_FILTER 0x2800
+#define GL_TEXTURE_MAX_LEVEL 0x813D
+#define GL_TEXTURE_MAX_LOD 0x813B
+#define GL_TEXTURE_MIN_FILTER 0x2801
+#define GL_TEXTURE_MIN_LOD 0x813A
+#define GL_TEXTURE_RECTANGLE 0x84F5
+#define GL_TEXTURE_RED_SIZE 0x805C
+#define GL_TEXTURE_RED_TYPE 0x8C10
+#define GL_TEXTURE_SAMPLES 0x9106
+#define GL_TEXTURE_SHARED_SIZE 0x8C3F
+#define GL_TEXTURE_STENCIL_SIZE 0x88F1
+#define GL_TEXTURE_SWIZZLE_A 0x8E45
+#define GL_TEXTURE_SWIZZLE_B 0x8E44
+#define GL_TEXTURE_SWIZZLE_G 0x8E43
+#define GL_TEXTURE_SWIZZLE_R 0x8E42
+#define GL_TEXTURE_SWIZZLE_RGBA 0x8E46
+#define GL_TEXTURE_WIDTH 0x1000
+#define GL_TEXTURE_WRAP_R 0x8072
+#define GL_TEXTURE_WRAP_S 0x2802
+#define GL_TEXTURE_WRAP_T 0x2803
+#define GL_TIMEOUT_EXPIRED 0x911B
+#define GL_TIMEOUT_IGNORED 0xFFFFFFFFFFFFFFFF
+#define GL_TIMESTAMP 0x8E28
+#define GL_TIME_ELAPSED 0x88BF
+#define GL_TRANSFORM_FEEDBACK_BUFFER 0x8C8E
+#define GL_TRANSFORM_FEEDBACK_BUFFER_BINDING 0x8C8F
+#define GL_TRANSFORM_FEEDBACK_BUFFER_MODE 0x8C7F
+#define GL_TRANSFORM_FEEDBACK_BUFFER_SIZE 0x8C85
+#define GL_TRANSFORM_FEEDBACK_BUFFER_START 0x8C84
+#define GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN 0x8C88
+#define GL_TRANSFORM_FEEDBACK_VARYINGS 0x8C83
+#define GL_TRANSFORM_FEEDBACK_VARYING_MAX_LENGTH 0x8C76
+#define GL_TRIANGLES 0x0004
+#define GL_TRIANGLES_ADJACENCY 0x000C
+#define GL_TRIANGLE_FAN 0x0006
+#define GL_TRIANGLE_STRIP 0x0005
+#define GL_TRIANGLE_STRIP_ADJACENCY 0x000D
+#define GL_TRUE 1
+#define GL_UNIFORM_ARRAY_STRIDE 0x8A3C
+#define GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS 0x8A42
+#define GL_UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES 0x8A43
+#define GL_UNIFORM_BLOCK_BINDING 0x8A3F
+#define GL_UNIFORM_BLOCK_DATA_SIZE 0x8A40
+#define GL_UNIFORM_BLOCK_INDEX 0x8A3A
+#define GL_UNIFORM_BLOCK_NAME_LENGTH 0x8A41
+#define GL_UNIFORM_BLOCK_REFERENCED_BY_FRAGMENT_SHADER 0x8A46
+#define GL_UNIFORM_BLOCK_REFERENCED_BY_GEOMETRY_SHADER 0x8A45
+#define GL_UNIFORM_BLOCK_REFERENCED_BY_VERTEX_SHADER 0x8A44
+#define GL_UNIFORM_BUFFER 0x8A11
+#define GL_UNIFORM_BUFFER_BINDING 0x8A28
+#define GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT 0x8A34
+#define GL_UNIFORM_BUFFER_SIZE 0x8A2A
+#define GL_UNIFORM_BUFFER_START 0x8A29
+#define GL_UNIFORM_IS_ROW_MAJOR 0x8A3E
+#define GL_UNIFORM_MATRIX_STRIDE 0x8A3D
+#define GL_UNIFORM_NAME_LENGTH 0x8A39
+#define GL_UNIFORM_OFFSET 0x8A3B
+#define GL_UNIFORM_SIZE 0x8A38
+#define GL_UNIFORM_TYPE 0x8A37
+#define GL_UNPACK_ALIGNMENT 0x0CF5
+#define GL_UNPACK_IMAGE_HEIGHT 0x806E
+#define GL_UNPACK_LSB_FIRST 0x0CF1
+#define GL_UNPACK_ROW_LENGTH 0x0CF2
+#define GL_UNPACK_SKIP_IMAGES 0x806D
+#define GL_UNPACK_SKIP_PIXELS 0x0CF4
+#define GL_UNPACK_SKIP_ROWS 0x0CF3
+#define GL_UNPACK_SWAP_BYTES 0x0CF0
+#define GL_UNSIGNALED 0x9118
+#define GL_UNSIGNED_BYTE 0x1401
+#define GL_UNSIGNED_BYTE_2_3_3_REV 0x8362
+#define GL_UNSIGNED_BYTE_3_3_2 0x8032
+#define GL_UNSIGNED_INT 0x1405
+#define GL_UNSIGNED_INT_10F_11F_11F_REV 0x8C3B
+#define GL_UNSIGNED_INT_10_10_10_2 0x8036
+#define GL_UNSIGNED_INT_24_8 0x84FA
+#define GL_UNSIGNED_INT_2_10_10_10_REV 0x8368
+#define GL_UNSIGNED_INT_5_9_9_9_REV 0x8C3E
+#define GL_UNSIGNED_INT_8_8_8_8 0x8035
+#define GL_UNSIGNED_INT_8_8_8_8_REV 0x8367
+#define GL_UNSIGNED_INT_SAMPLER_1D 0x8DD1
+#define GL_UNSIGNED_INT_SAMPLER_1D_ARRAY 0x8DD6
+#define GL_UNSIGNED_INT_SAMPLER_2D 0x8DD2
+#define GL_UNSIGNED_INT_SAMPLER_2D_ARRAY 0x8DD7
+#define GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE 0x910A
+#define GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE_ARRAY 0x910D
+#define GL_UNSIGNED_INT_SAMPLER_2D_RECT 0x8DD5
+#define GL_UNSIGNED_INT_SAMPLER_3D 0x8DD3
+#define GL_UNSIGNED_INT_SAMPLER_BUFFER 0x8DD8
+#define GL_UNSIGNED_INT_SAMPLER_CUBE 0x8DD4
+#define GL_UNSIGNED_INT_VEC2 0x8DC6
+#define GL_UNSIGNED_INT_VEC3 0x8DC7
+#define GL_UNSIGNED_INT_VEC4 0x8DC8
+#define GL_UNSIGNED_NORMALIZED 0x8C17
+#define GL_UNSIGNED_SHORT 0x1403
+#define GL_UNSIGNED_SHORT_1_5_5_5_REV 0x8366
+#define GL_UNSIGNED_SHORT_4_4_4_4 0x8033
+#define GL_UNSIGNED_SHORT_4_4_4_4_REV 0x8365
+#define GL_UNSIGNED_SHORT_5_5_5_1 0x8034
+#define GL_UNSIGNED_SHORT_5_6_5 0x8363
+#define GL_UNSIGNED_SHORT_5_6_5_REV 0x8364
+#define GL_UPPER_LEFT 0x8CA2
+#define GL_VALIDATE_STATUS 0x8B83
+#define GL_VENDOR 0x1F00
+#define GL_VERSION 0x1F02
+#define GL_VERTEX_ARRAY_BINDING 0x85B5
+#define GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING 0x889F
+#define GL_VERTEX_ATTRIB_ARRAY_DIVISOR 0x88FE
+#define GL_VERTEX_ATTRIB_ARRAY_ENABLED 0x8622
+#define GL_VERTEX_ATTRIB_ARRAY_INTEGER 0x88FD
+#define GL_VERTEX_ATTRIB_ARRAY_NORMALIZED 0x886A
+#define GL_VERTEX_ATTRIB_ARRAY_POINTER 0x8645
+#define GL_VERTEX_ATTRIB_ARRAY_SIZE 0x8623
+#define GL_VERTEX_ATTRIB_ARRAY_STRIDE 0x8624
+#define GL_VERTEX_ATTRIB_ARRAY_TYPE 0x8625
+#define GL_VERTEX_PROGRAM_POINT_SIZE 0x8642
+#define GL_VERTEX_SHADER 0x8B31
+#define GL_VIEWPORT 0x0BA2
+#define GL_WAIT_FAILED 0x911D
+#define GL_WRITE_ONLY 0x88B9
+#define GL_XOR 0x1506
+#define GL_ZERO 0
+
+
+#ifndef __khrplatform_h_
+#define __khrplatform_h_
+
+/*
+** Copyright (c) 2008-2018 The Khronos Group Inc.
+**
+** Permission is hereby granted, free of charge, to any person obtaining a
+** copy of this software and/or associated documentation files (the
+** "Materials"), to deal in the Materials without restriction, including
+** without limitation the rights to use, copy, modify, merge, publish,
+** distribute, sublicense, and/or sell copies of the Materials, and to
+** permit persons to whom the Materials are furnished to do so, subject to
+** the following conditions:
+**
+** The above copyright notice and this permission notice shall be included
+** in all copies or substantial portions of the Materials.
+**
+** THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
+*/
+
+/* Khronos platform-specific types and definitions.
+ *
+ * The master copy of khrplatform.h is maintained in the Khronos EGL
+ * Registry repository at https://github.com/KhronosGroup/EGL-Registry
+ * The last semantic modification to khrplatform.h was at commit ID:
+ *      67a3e0864c2d75ea5287b9f3d2eb74a745936692
+ *
+ * Adopters may modify this file to suit their platform. Adopters are
+ * encouraged to submit platform specific modifications to the Khronos
+ * group so that they can be included in future versions of this file.
+ * Please submit changes by filing pull requests or issues on
+ * the EGL Registry repository linked above.
+ *
+ *
+ * See the Implementer's Guidelines for information about where this file
+ * should be located on your system and for more details of its use:
+ *    http://www.khronos.org/registry/implementers_guide.pdf
+ *
+ * This file should be included as
+ *        #include <KHR/khrplatform.h>
+ * by Khronos client API header files that use its types and defines.
+ *
+ * The types in khrplatform.h should only be used to define API-specific types.
+ *
+ * Types defined in khrplatform.h:
+ *    khronos_int8_t              signed   8  bit
+ *    khronos_uint8_t             unsigned 8  bit
+ *    khronos_int16_t             signed   16 bit
+ *    khronos_uint16_t            unsigned 16 bit
+ *    khronos_int32_t             signed   32 bit
+ *    khronos_uint32_t            unsigned 32 bit
+ *    khronos_int64_t             signed   64 bit
+ *    khronos_uint64_t            unsigned 64 bit
+ *    khronos_intptr_t            signed   same number of bits as a pointer
+ *    khronos_uintptr_t           unsigned same number of bits as a pointer
+ *    khronos_ssize_t             signed   size
+ *    khronos_usize_t             unsigned size
+ *    khronos_float_t             signed   32 bit floating point
+ *    khronos_time_ns_t           unsigned 64 bit time in nanoseconds
+ *    khronos_utime_nanoseconds_t unsigned time interval or absolute time in
+ *                                         nanoseconds
+ *    khronos_stime_nanoseconds_t signed time interval in nanoseconds
+ *    khronos_boolean_enum_t      enumerated boolean type. This should
+ *      only be used as a base type when a client API's boolean type is
+ *      an enum. Client APIs which use an integer or other type for
+ *      booleans cannot use this as the base type for their boolean.
+ *
+ * Tokens defined in khrplatform.h:
+ *
+ *    KHRONOS_FALSE, KHRONOS_TRUE Enumerated boolean false/true values.
+ *
+ *    KHRONOS_SUPPORT_INT64 is 1 if 64 bit integers are supported; otherwise 0.
+ *    KHRONOS_SUPPORT_FLOAT is 1 if floats are supported; otherwise 0.
+ *
+ * Calling convention macros defined in this file:
+ *    KHRONOS_APICALL
+ *    KHRONOS_GLAD_API_PTR
+ *    KHRONOS_APIATTRIBUTES
+ *
+ * These may be used in function prototypes as:
+ *
+ *      KHRONOS_APICALL void KHRONOS_GLAD_API_PTR funcname(
+ *                                  int arg1,
+ *                                  int arg2) KHRONOS_APIATTRIBUTES;
+ */
+
+#if defined(__SCITECH_SNAP__) && !defined(KHRONOS_STATIC)
+#   define KHRONOS_STATIC 1
+#endif
+
+/*-------------------------------------------------------------------------
+ * Definition of KHRONOS_APICALL
+ *-------------------------------------------------------------------------
+ * This precedes the return type of the function in the function prototype.
+ */
+#if defined(KHRONOS_STATIC)
+    /* If the preprocessor constant KHRONOS_STATIC is defined, make the
+     * header compatible with static linking. */
+#   define KHRONOS_APICALL
+#elif defined(_WIN32)
+#   define KHRONOS_APICALL __declspec(dllimport)
+#elif defined (__SYMBIAN32__)
+#   define KHRONOS_APICALL IMPORT_C
+#elif defined(__ANDROID__)
+#   define KHRONOS_APICALL __attribute__((visibility("default")))
+#else
+#   define KHRONOS_APICALL
+#endif
+
+/*-------------------------------------------------------------------------
+ * Definition of KHRONOS_GLAD_API_PTR
+ *-------------------------------------------------------------------------
+ * This follows the return type of the function  and precedes the function
+ * name in the function prototype.
+ */
+#if defined(_WIN32) && !defined(_WIN32_WCE) && !defined(__SCITECH_SNAP__)
+    /* Win32 but not WinCE */
+#   define KHRONOS_GLAD_API_PTR __stdcall
+#else
+#   define KHRONOS_GLAD_API_PTR
+#endif
+
+/*-------------------------------------------------------------------------
+ * Definition of KHRONOS_APIATTRIBUTES
+ *-------------------------------------------------------------------------
+ * This follows the closing parenthesis of the function prototype arguments.
+ */
+#if defined (__ARMCC_2__)
+#define KHRONOS_APIATTRIBUTES __softfp
+#else
+#define KHRONOS_APIATTRIBUTES
+#endif
+
+/*-------------------------------------------------------------------------
+ * basic type definitions
+ *-----------------------------------------------------------------------*/
+#if (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) || defined(__GNUC__) || defined(__SCO__) || defined(__USLC__)
+
+
+/*
+ * Using <stdint.h>
+ */
+#include <stdint.h>
+typedef int32_t                 khronos_int32_t;
+typedef uint32_t                khronos_uint32_t;
+typedef int64_t                 khronos_int64_t;
+typedef uint64_t                khronos_uint64_t;
+#define KHRONOS_SUPPORT_INT64   1
+#define KHRONOS_SUPPORT_FLOAT   1
+/*
+ * To support platform where unsigned long cannot be used interchangeably with
+ * inptr_t (e.g. CHERI-extended ISAs), we can use the stdint.h intptr_t.
+ * Ideally, we could just use (u)intptr_t everywhere, but this could result in
+ * ABI breakage if khronos_uintptr_t is changed from unsigned long to
+ * unsigned long long or similar (this results in different C++ name mangling).
+ * To avoid changes for existing platforms, we restrict usage of intptr_t to
+ * platforms where the size of a pointer is larger than the size of long.
+ */
+#if defined(__SIZEOF_LONG__) && defined(__SIZEOF_POINTER__)
+#if __SIZEOF_POINTER__ > __SIZEOF_LONG__
+#define KHRONOS_USE_INTPTR_T
+#endif
+#endif
+
+#elif defined(__VMS ) || defined(__sgi)
+
+/*
+ * Using <inttypes.h>
+ */
+#include <inttypes.h>
+typedef int32_t                 khronos_int32_t;
+typedef uint32_t                khronos_uint32_t;
+typedef int64_t                 khronos_int64_t;
+typedef uint64_t                khronos_uint64_t;
+#define KHRONOS_SUPPORT_INT64   1
+#define KHRONOS_SUPPORT_FLOAT   1
+
+#elif defined(_WIN32) && !defined(__SCITECH_SNAP__)
+
+/*
+ * Win32
+ */
+typedef __int32                 khronos_int32_t;
+typedef unsigned __int32        khronos_uint32_t;
+typedef __int64                 khronos_int64_t;
+typedef unsigned __int64        khronos_uint64_t;
+#define KHRONOS_SUPPORT_INT64   1
+#define KHRONOS_SUPPORT_FLOAT   1
+
+#elif defined(__sun__) || defined(__digital__)
+
+/*
+ * Sun or Digital
+ */
+typedef int                     khronos_int32_t;
+typedef unsigned int            khronos_uint32_t;
+#if defined(__arch64__) || defined(_LP64)
+typedef long int                khronos_int64_t;
+typedef unsigned long int       khronos_uint64_t;
+#else
+typedef long long int           khronos_int64_t;
+typedef unsigned long long int  khronos_uint64_t;
+#endif /* __arch64__ */
+#define KHRONOS_SUPPORT_INT64   1
+#define KHRONOS_SUPPORT_FLOAT   1
+
+#elif 0
+
+/*
+ * Hypothetical platform with no float or int64 support
+ */
+typedef int                     khronos_int32_t;
+typedef unsigned int            khronos_uint32_t;
+#define KHRONOS_SUPPORT_INT64   0
+#define KHRONOS_SUPPORT_FLOAT   0
+
+#else
+
+/*
+ * Generic fallback
+ */
+#include <stdint.h>
+typedef int32_t                 khronos_int32_t;
+typedef uint32_t                khronos_uint32_t;
+typedef int64_t                 khronos_int64_t;
+typedef uint64_t                khronos_uint64_t;
+#define KHRONOS_SUPPORT_INT64   1
+#define KHRONOS_SUPPORT_FLOAT   1
+
+#endif
+
+
+/*
+ * Types that are (so far) the same on all platforms
+ */
+typedef signed   char          khronos_int8_t;
+typedef unsigned char          khronos_uint8_t;
+typedef signed   short int     khronos_int16_t;
+typedef unsigned short int     khronos_uint16_t;
+
+/*
+ * Types that differ between LLP64 and LP64 architectures - in LLP64,
+ * pointers are 64 bits, but 'long' is still 32 bits. Win64 appears
+ * to be the only LLP64 architecture in current use.
+ */
+#ifdef KHRONOS_USE_INTPTR_T
+typedef intptr_t               khronos_intptr_t;
+typedef uintptr_t              khronos_uintptr_t;
+#elif defined(_WIN64)
+typedef signed   long long int khronos_intptr_t;
+typedef unsigned long long int khronos_uintptr_t;
+#else
+typedef signed   long  int     khronos_intptr_t;
+typedef unsigned long  int     khronos_uintptr_t;
+#endif
+
+#if defined(_WIN64)
+typedef signed   long long int khronos_ssize_t;
+typedef unsigned long long int khronos_usize_t;
+#else
+typedef signed   long  int     khronos_ssize_t;
+typedef unsigned long  int     khronos_usize_t;
+#endif
+
+#if KHRONOS_SUPPORT_FLOAT
+/*
+ * Float type
+ */
+typedef          float         khronos_float_t;
+#endif
+
+#if KHRONOS_SUPPORT_INT64
+/* Time types
+ *
+ * These types can be used to represent a time interval in nanoseconds or
+ * an absolute Unadjusted System Time.  Unadjusted System Time is the number
+ * of nanoseconds since some arbitrary system event (e.g. since the last
+ * time the system booted).  The Unadjusted System Time is an unsigned
+ * 64 bit value that wraps back to 0 every 584 years.  Time intervals
+ * may be either signed or unsigned.
+ */
+typedef khronos_uint64_t       khronos_utime_nanoseconds_t;
+typedef khronos_int64_t        khronos_stime_nanoseconds_t;
+#endif
+
+/*
+ * Dummy value used to pad enum types to 32 bits.
+ */
+#ifndef KHRONOS_MAX_ENUM
+#define KHRONOS_MAX_ENUM 0x7FFFFFFF
+#endif
+
+/*
+ * Enumerated boolean type
+ *
+ * Values other than zero should be considered to be true.  Therefore
+ * comparisons should not be made against KHRONOS_TRUE.
+ */
+typedef enum {
+    KHRONOS_FALSE = 0,
+    KHRONOS_TRUE  = 1,
+    KHRONOS_BOOLEAN_ENUM_FORCE_SIZE = KHRONOS_MAX_ENUM
+} khronos_boolean_enum_t;
+
+#endif /* __khrplatform_h_ */
+typedef unsigned int GLenum;
+typedef unsigned char GLboolean;
+typedef unsigned int GLbitfield;
+typedef void GLvoid;
+typedef khronos_int8_t GLbyte;
+typedef khronos_uint8_t GLubyte;
+typedef khronos_int16_t GLshort;
+typedef khronos_uint16_t GLushort;
+typedef int GLint;
+typedef unsigned int GLuint;
+typedef khronos_int32_t GLclampx;
+typedef int GLsizei;
+typedef khronos_float_t GLfloat;
+typedef khronos_float_t GLclampf;
+typedef double GLdouble;
+typedef double GLclampd;
+typedef void *GLeglClientBufferEXT;
+typedef void *GLeglImageOES;
+typedef char GLchar;
+typedef char GLcharARB;
+#ifdef __APPLE__
+typedef void *GLhandleARB;
+#else
+typedef unsigned int GLhandleARB;
+#endif
+typedef khronos_uint16_t GLhalf;
+typedef khronos_uint16_t GLhalfARB;
+typedef khronos_int32_t GLfixed;
+#if defined(__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__) && (__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ > 1060)
+typedef khronos_intptr_t GLintptr;
+#else
+typedef khronos_intptr_t GLintptr;
+#endif
+#if defined(__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__) && (__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ > 1060)
+typedef khronos_intptr_t GLintptrARB;
+#else
+typedef khronos_intptr_t GLintptrARB;
+#endif
+#if defined(__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__) && (__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ > 1060)
+typedef khronos_ssize_t GLsizeiptr;
+#else
+typedef khronos_ssize_t GLsizeiptr;
+#endif
+#if defined(__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__) && (__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ > 1060)
+typedef khronos_ssize_t GLsizeiptrARB;
+#else
+typedef khronos_ssize_t GLsizeiptrARB;
+#endif
+typedef khronos_int64_t GLint64;
+typedef khronos_int64_t GLint64EXT;
+typedef khronos_uint64_t GLuint64;
+typedef khronos_uint64_t GLuint64EXT;
+typedef struct __GLsync *GLsync;
+struct _cl_context;
+struct _cl_event;
+typedef void (GLAD_API_PTR *GLDEBUGPROC)(GLenum source,GLenum type,GLuint id,GLenum severity,GLsizei length,const GLchar *message,const void *userParam);
+typedef void (GLAD_API_PTR *GLDEBUGPROCARB)(GLenum source,GLenum type,GLuint id,GLenum severity,GLsizei length,const GLchar *message,const void *userParam);
+typedef void (GLAD_API_PTR *GLDEBUGPROCKHR)(GLenum source,GLenum type,GLuint id,GLenum severity,GLsizei length,const GLchar *message,const void *userParam);
+typedef void (GLAD_API_PTR *GLDEBUGPROCAMD)(GLuint id,GLenum category,GLenum severity,GLsizei length,const GLchar *message,void *userParam);
+typedef unsigned short GLhalfNV;
+typedef GLintptr GLvdpauSurfaceNV;
+typedef void (GLAD_API_PTR *GLVULKANPROCNV)(void);
+
+
+#define GL_VERSION_1_0 1
+GLAD_API_CALL int GLAD_GL_VERSION_1_0;
+#define GL_VERSION_1_1 1
+GLAD_API_CALL int GLAD_GL_VERSION_1_1;
+#define GL_VERSION_1_2 1
+GLAD_API_CALL int GLAD_GL_VERSION_1_2;
+#define GL_VERSION_1_3 1
+GLAD_API_CALL int GLAD_GL_VERSION_1_3;
+#define GL_VERSION_1_4 1
+GLAD_API_CALL int GLAD_GL_VERSION_1_4;
+#define GL_VERSION_1_5 1
+GLAD_API_CALL int GLAD_GL_VERSION_1_5;
+#define GL_VERSION_2_0 1
+GLAD_API_CALL int GLAD_GL_VERSION_2_0;
+#define GL_VERSION_2_1 1
+GLAD_API_CALL int GLAD_GL_VERSION_2_1;
+#define GL_VERSION_3_0 1
+GLAD_API_CALL int GLAD_GL_VERSION_3_0;
+#define GL_VERSION_3_1 1
+GLAD_API_CALL int GLAD_GL_VERSION_3_1;
+#define GL_VERSION_3_2 1
+GLAD_API_CALL int GLAD_GL_VERSION_3_2;
+#define GL_VERSION_3_3 1
+GLAD_API_CALL int GLAD_GL_VERSION_3_3;
+
+
+typedef void (GLAD_API_PTR *PFNGLACTIVETEXTUREPROC)(GLenum texture);
+typedef void (GLAD_API_PTR *PFNGLATTACHSHADERPROC)(GLuint program, GLuint shader);
+typedef void (GLAD_API_PTR *PFNGLBEGINCONDITIONALRENDERPROC)(GLuint id, GLenum mode);
+typedef void (GLAD_API_PTR *PFNGLBEGINQUERYPROC)(GLenum target, GLuint id);
+typedef void (GLAD_API_PTR *PFNGLBEGINTRANSFORMFEEDBACKPROC)(GLenum primitiveMode);
+typedef void (GLAD_API_PTR *PFNGLBINDATTRIBLOCATIONPROC)(GLuint program, GLuint index, const GLchar * name);
+typedef void (GLAD_API_PTR *PFNGLBINDBUFFERPROC)(GLenum target, GLuint buffer);
+typedef void (GLAD_API_PTR *PFNGLBINDBUFFERBASEPROC)(GLenum target, GLuint index, GLuint buffer);
+typedef void (GLAD_API_PTR *PFNGLBINDBUFFERRANGEPROC)(GLenum target, GLuint index, GLuint buffer, GLintptr offset, GLsizeiptr size);
+typedef void (GLAD_API_PTR *PFNGLBINDFRAGDATALOCATIONPROC)(GLuint program, GLuint color, const GLchar * name);
+typedef void (GLAD_API_PTR *PFNGLBINDFRAGDATALOCATIONINDEXEDPROC)(GLuint program, GLuint colorNumber, GLuint index, const GLchar * name);
+typedef void (GLAD_API_PTR *PFNGLBINDFRAMEBUFFERPROC)(GLenum target, GLuint framebuffer);
+typedef void (GLAD_API_PTR *PFNGLBINDRENDERBUFFERPROC)(GLenum target, GLuint renderbuffer);
+typedef void (GLAD_API_PTR *PFNGLBINDSAMPLERPROC)(GLuint unit, GLuint sampler);
+typedef void (GLAD_API_PTR *PFNGLBINDTEXTUREPROC)(GLenum target, GLuint texture);
+typedef void (GLAD_API_PTR *PFNGLBINDVERTEXARRAYPROC)(GLuint array);
+typedef void (GLAD_API_PTR *PFNGLBLENDCOLORPROC)(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha);
+typedef void (GLAD_API_PTR *PFNGLBLENDEQUATIONPROC)(GLenum mode);
+typedef void (GLAD_API_PTR *PFNGLBLENDEQUATIONSEPARATEPROC)(GLenum modeRGB, GLenum modeAlpha);
+typedef void (GLAD_API_PTR *PFNGLBLENDFUNCPROC)(GLenum sfactor, GLenum dfactor);
+typedef void (GLAD_API_PTR *PFNGLBLENDFUNCSEPARATEPROC)(GLenum sfactorRGB, GLenum dfactorRGB, GLenum sfactorAlpha, GLenum dfactorAlpha);
+typedef void (GLAD_API_PTR *PFNGLBLITFRAMEBUFFERPROC)(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter);
+typedef void (GLAD_API_PTR *PFNGLBUFFERDATAPROC)(GLenum target, GLsizeiptr size, const void * data, GLenum usage);
+typedef void (GLAD_API_PTR *PFNGLBUFFERSUBDATAPROC)(GLenum target, GLintptr offset, GLsizeiptr size, const void * data);
+typedef GLenum (GLAD_API_PTR *PFNGLCHECKFRAMEBUFFERSTATUSPROC)(GLenum target);
+typedef void (GLAD_API_PTR *PFNGLCLAMPCOLORPROC)(GLenum target, GLenum clamp);
+typedef void (GLAD_API_PTR *PFNGLCLEARPROC)(GLbitfield mask);
+typedef void (GLAD_API_PTR *PFNGLCLEARBUFFERFIPROC)(GLenum buffer, GLint drawbuffer, GLfloat depth, GLint stencil);
+typedef void (GLAD_API_PTR *PFNGLCLEARBUFFERFVPROC)(GLenum buffer, GLint drawbuffer, const GLfloat * value);
+typedef void (GLAD_API_PTR *PFNGLCLEARBUFFERIVPROC)(GLenum buffer, GLint drawbuffer, const GLint * value);
+typedef void (GLAD_API_PTR *PFNGLCLEARBUFFERUIVPROC)(GLenum buffer, GLint drawbuffer, const GLuint * value);
+typedef void (GLAD_API_PTR *PFNGLCLEARCOLORPROC)(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha);
+typedef void (GLAD_API_PTR *PFNGLCLEARDEPTHPROC)(GLdouble depth);
+typedef void (GLAD_API_PTR *PFNGLCLEARSTENCILPROC)(GLint s);
+typedef GLenum (GLAD_API_PTR *PFNGLCLIENTWAITSYNCPROC)(GLsync sync, GLbitfield flags, GLuint64 timeout);
+typedef void (GLAD_API_PTR *PFNGLCOLORMASKPROC)(GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha);
+typedef void (GLAD_API_PTR *PFNGLCOLORMASKIPROC)(GLuint index, GLboolean r, GLboolean g, GLboolean b, GLboolean a);
+typedef void (GLAD_API_PTR *PFNGLCOMPILESHADERPROC)(GLuint shader);
+typedef void (GLAD_API_PTR *PFNGLCOMPRESSEDTEXIMAGE1DPROC)(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLint border, GLsizei imageSize, const void * data);
+typedef void (GLAD_API_PTR *PFNGLCOMPRESSEDTEXIMAGE2DPROC)(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const void * data);
+typedef void (GLAD_API_PTR *PFNGLCOMPRESSEDTEXIMAGE3DPROC)(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const void * data);
+typedef void (GLAD_API_PTR *PFNGLCOMPRESSEDTEXSUBIMAGE1DPROC)(GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLsizei imageSize, const void * data);
+typedef void (GLAD_API_PTR *PFNGLCOMPRESSEDTEXSUBIMAGE2DPROC)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void * data);
+typedef void (GLAD_API_PTR *PFNGLCOMPRESSEDTEXSUBIMAGE3DPROC)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void * data);
+typedef void (GLAD_API_PTR *PFNGLCOPYBUFFERSUBDATAPROC)(GLenum readTarget, GLenum writeTarget, GLintptr readOffset, GLintptr writeOffset, GLsizeiptr size);
+typedef void (GLAD_API_PTR *PFNGLCOPYTEXIMAGE1DPROC)(GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLint border);
+typedef void (GLAD_API_PTR *PFNGLCOPYTEXIMAGE2DPROC)(GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border);
+typedef void (GLAD_API_PTR *PFNGLCOPYTEXSUBIMAGE1DPROC)(GLenum target, GLint level, GLint xoffset, GLint x, GLint y, GLsizei width);
+typedef void (GLAD_API_PTR *PFNGLCOPYTEXSUBIMAGE2DPROC)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height);
+typedef void (GLAD_API_PTR *PFNGLCOPYTEXSUBIMAGE3DPROC)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height);
+typedef GLuint (GLAD_API_PTR *PFNGLCREATEPROGRAMPROC)(void);
+typedef GLuint (GLAD_API_PTR *PFNGLCREATESHADERPROC)(GLenum type);
+typedef void (GLAD_API_PTR *PFNGLCULLFACEPROC)(GLenum mode);
+typedef void (GLAD_API_PTR *PFNGLDELETEBUFFERSPROC)(GLsizei n, const GLuint * buffers);
+typedef void (GLAD_API_PTR *PFNGLDELETEFRAMEBUFFERSPROC)(GLsizei n, const GLuint * framebuffers);
+typedef void (GLAD_API_PTR *PFNGLDELETEPROGRAMPROC)(GLuint program);
+typedef void (GLAD_API_PTR *PFNGLDELETEQUERIESPROC)(GLsizei n, const GLuint * ids);
+typedef void (GLAD_API_PTR *PFNGLDELETERENDERBUFFERSPROC)(GLsizei n, const GLuint * renderbuffers);
+typedef void (GLAD_API_PTR *PFNGLDELETESAMPLERSPROC)(GLsizei count, const GLuint * samplers);
+typedef void (GLAD_API_PTR *PFNGLDELETESHADERPROC)(GLuint shader);
+typedef void (GLAD_API_PTR *PFNGLDELETESYNCPROC)(GLsync sync);
+typedef void (GLAD_API_PTR *PFNGLDELETETEXTURESPROC)(GLsizei n, const GLuint * textures);
+typedef void (GLAD_API_PTR *PFNGLDELETEVERTEXARRAYSPROC)(GLsizei n, const GLuint * arrays);
+typedef void (GLAD_API_PTR *PFNGLDEPTHFUNCPROC)(GLenum func);
+typedef void (GLAD_API_PTR *PFNGLDEPTHMASKPROC)(GLboolean flag);
+typedef void (GLAD_API_PTR *PFNGLDEPTHRANGEPROC)(GLdouble n, GLdouble f);
+typedef void (GLAD_API_PTR *PFNGLDETACHSHADERPROC)(GLuint program, GLuint shader);
+typedef void (GLAD_API_PTR *PFNGLDISABLEPROC)(GLenum cap);
+typedef void (GLAD_API_PTR *PFNGLDISABLEVERTEXATTRIBARRAYPROC)(GLuint index);
+typedef void (GLAD_API_PTR *PFNGLDISABLEIPROC)(GLenum target, GLuint index);
+typedef void (GLAD_API_PTR *PFNGLDRAWARRAYSPROC)(GLenum mode, GLint first, GLsizei count);
+typedef void (GLAD_API_PTR *PFNGLDRAWARRAYSINSTANCEDPROC)(GLenum mode, GLint first, GLsizei count, GLsizei instancecount);
+typedef void (GLAD_API_PTR *PFNGLDRAWBUFFERPROC)(GLenum buf);
+typedef void (GLAD_API_PTR *PFNGLDRAWBUFFERSPROC)(GLsizei n, const GLenum * bufs);
+typedef void (GLAD_API_PTR *PFNGLDRAWELEMENTSPROC)(GLenum mode, GLsizei count, GLenum type, const void * indices);
+typedef void (GLAD_API_PTR *PFNGLDRAWELEMENTSBASEVERTEXPROC)(GLenum mode, GLsizei count, GLenum type, const void * indices, GLint basevertex);
+typedef void (GLAD_API_PTR *PFNGLDRAWELEMENTSINSTANCEDPROC)(GLenum mode, GLsizei count, GLenum type, const void * indices, GLsizei instancecount);
+typedef void (GLAD_API_PTR *PFNGLDRAWELEMENTSINSTANCEDBASEVERTEXPROC)(GLenum mode, GLsizei count, GLenum type, const void * indices, GLsizei instancecount, GLint basevertex);
+typedef void (GLAD_API_PTR *PFNGLDRAWRANGEELEMENTSPROC)(GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const void * indices);
+typedef void (GLAD_API_PTR *PFNGLDRAWRANGEELEMENTSBASEVERTEXPROC)(GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const void * indices, GLint basevertex);
+typedef void (GLAD_API_PTR *PFNGLENABLEPROC)(GLenum cap);
+typedef void (GLAD_API_PTR *PFNGLENABLEVERTEXATTRIBARRAYPROC)(GLuint index);
+typedef void (GLAD_API_PTR *PFNGLENABLEIPROC)(GLenum target, GLuint index);
+typedef void (GLAD_API_PTR *PFNGLENDCONDITIONALRENDERPROC)(void);
+typedef void (GLAD_API_PTR *PFNGLENDQUERYPROC)(GLenum target);
+typedef void (GLAD_API_PTR *PFNGLENDTRANSFORMFEEDBACKPROC)(void);
+typedef GLsync (GLAD_API_PTR *PFNGLFENCESYNCPROC)(GLenum condition, GLbitfield flags);
+typedef void (GLAD_API_PTR *PFNGLFINISHPROC)(void);
+typedef void (GLAD_API_PTR *PFNGLFLUSHPROC)(void);
+typedef void (GLAD_API_PTR *PFNGLFLUSHMAPPEDBUFFERRANGEPROC)(GLenum target, GLintptr offset, GLsizeiptr length);
+typedef void (GLAD_API_PTR *PFNGLFRAMEBUFFERRENDERBUFFERPROC)(GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer);
+typedef void (GLAD_API_PTR *PFNGLFRAMEBUFFERTEXTUREPROC)(GLenum target, GLenum attachment, GLuint texture, GLint level);
+typedef void (GLAD_API_PTR *PFNGLFRAMEBUFFERTEXTURE1DPROC)(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level);
+typedef void (GLAD_API_PTR *PFNGLFRAMEBUFFERTEXTURE2DPROC)(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level);
+typedef void (GLAD_API_PTR *PFNGLFRAMEBUFFERTEXTURE3DPROC)(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLint zoffset);
+typedef void (GLAD_API_PTR *PFNGLFRAMEBUFFERTEXTURELAYERPROC)(GLenum target, GLenum attachment, GLuint texture, GLint level, GLint layer);
+typedef void (GLAD_API_PTR *PFNGLFRONTFACEPROC)(GLenum mode);
+typedef void (GLAD_API_PTR *PFNGLGENBUFFERSPROC)(GLsizei n, GLuint * buffers);
+typedef void (GLAD_API_PTR *PFNGLGENFRAMEBUFFERSPROC)(GLsizei n, GLuint * framebuffers);
+typedef void (GLAD_API_PTR *PFNGLGENQUERIESPROC)(GLsizei n, GLuint * ids);
+typedef void (GLAD_API_PTR *PFNGLGENRENDERBUFFERSPROC)(GLsizei n, GLuint * renderbuffers);
+typedef void (GLAD_API_PTR *PFNGLGENSAMPLERSPROC)(GLsizei count, GLuint * samplers);
+typedef void (GLAD_API_PTR *PFNGLGENTEXTURESPROC)(GLsizei n, GLuint * textures);
+typedef void (GLAD_API_PTR *PFNGLGENVERTEXARRAYSPROC)(GLsizei n, GLuint * arrays);
+typedef void (GLAD_API_PTR *PFNGLGENERATEMIPMAPPROC)(GLenum target);
+typedef void (GLAD_API_PTR *PFNGLGETACTIVEATTRIBPROC)(GLuint program, GLuint index, GLsizei bufSize, GLsizei * length, GLint * size, GLenum * type, GLchar * name);
+typedef void (GLAD_API_PTR *PFNGLGETACTIVEUNIFORMPROC)(GLuint program, GLuint index, GLsizei bufSize, GLsizei * length, GLint * size, GLenum * type, GLchar * name);
+typedef void (GLAD_API_PTR *PFNGLGETACTIVEUNIFORMBLOCKNAMEPROC)(GLuint program, GLuint uniformBlockIndex, GLsizei bufSize, GLsizei * length, GLchar * uniformBlockName);
+typedef void (GLAD_API_PTR *PFNGLGETACTIVEUNIFORMBLOCKIVPROC)(GLuint program, GLuint uniformBlockIndex, GLenum pname, GLint * params);
+typedef void (GLAD_API_PTR *PFNGLGETACTIVEUNIFORMNAMEPROC)(GLuint program, GLuint uniformIndex, GLsizei bufSize, GLsizei * length, GLchar * uniformName);
+typedef void (GLAD_API_PTR *PFNGLGETACTIVEUNIFORMSIVPROC)(GLuint program, GLsizei uniformCount, const GLuint * uniformIndices, GLenum pname, GLint * params);
+typedef void (GLAD_API_PTR *PFNGLGETATTACHEDSHADERSPROC)(GLuint program, GLsizei maxCount, GLsizei * count, GLuint * shaders);
+typedef GLint (GLAD_API_PTR *PFNGLGETATTRIBLOCATIONPROC)(GLuint program, const GLchar * name);
+typedef void (GLAD_API_PTR *PFNGLGETBOOLEANI_VPROC)(GLenum target, GLuint index, GLboolean * data);
+typedef void (GLAD_API_PTR *PFNGLGETBOOLEANVPROC)(GLenum pname, GLboolean * data);
+typedef void (GLAD_API_PTR *PFNGLGETBUFFERPARAMETERI64VPROC)(GLenum target, GLenum pname, GLint64 * params);
+typedef void (GLAD_API_PTR *PFNGLGETBUFFERPARAMETERIVPROC)(GLenum target, GLenum pname, GLint * params);
+typedef void (GLAD_API_PTR *PFNGLGETBUFFERPOINTERVPROC)(GLenum target, GLenum pname, void ** params);
+typedef void (GLAD_API_PTR *PFNGLGETBUFFERSUBDATAPROC)(GLenum target, GLintptr offset, GLsizeiptr size, void * data);
+typedef void (GLAD_API_PTR *PFNGLGETCOMPRESSEDTEXIMAGEPROC)(GLenum target, GLint level, void * img);
+typedef void (GLAD_API_PTR *PFNGLGETDOUBLEVPROC)(GLenum pname, GLdouble * data);
+typedef GLenum (GLAD_API_PTR *PFNGLGETERRORPROC)(void);
+typedef void (GLAD_API_PTR *PFNGLGETFLOATVPROC)(GLenum pname, GLfloat * data);
+typedef GLint (GLAD_API_PTR *PFNGLGETFRAGDATAINDEXPROC)(GLuint program, const GLchar * name);
+typedef GLint (GLAD_API_PTR *PFNGLGETFRAGDATALOCATIONPROC)(GLuint program, const GLchar * name);
+typedef void (GLAD_API_PTR *PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVPROC)(GLenum target, GLenum attachment, GLenum pname, GLint * params);
+typedef void (GLAD_API_PTR *PFNGLGETINTEGER64I_VPROC)(GLenum target, GLuint index, GLint64 * data);
+typedef void (GLAD_API_PTR *PFNGLGETINTEGER64VPROC)(GLenum pname, GLint64 * data);
+typedef void (GLAD_API_PTR *PFNGLGETINTEGERI_VPROC)(GLenum target, GLuint index, GLint * data);
+typedef void (GLAD_API_PTR *PFNGLGETINTEGERVPROC)(GLenum pname, GLint * data);
+typedef void (GLAD_API_PTR *PFNGLGETMULTISAMPLEFVPROC)(GLenum pname, GLuint index, GLfloat * val);
+typedef void (GLAD_API_PTR *PFNGLGETPROGRAMINFOLOGPROC)(GLuint program, GLsizei bufSize, GLsizei * length, GLchar * infoLog);
+typedef void (GLAD_API_PTR *PFNGLGETPROGRAMIVPROC)(GLuint program, GLenum pname, GLint * params);
+typedef void (GLAD_API_PTR *PFNGLGETQUERYOBJECTI64VPROC)(GLuint id, GLenum pname, GLint64 * params);
+typedef void (GLAD_API_PTR *PFNGLGETQUERYOBJECTIVPROC)(GLuint id, GLenum pname, GLint * params);
+typedef void (GLAD_API_PTR *PFNGLGETQUERYOBJECTUI64VPROC)(GLuint id, GLenum pname, GLuint64 * params);
+typedef void (GLAD_API_PTR *PFNGLGETQUERYOBJECTUIVPROC)(GLuint id, GLenum pname, GLuint * params);
+typedef void (GLAD_API_PTR *PFNGLGETQUERYIVPROC)(GLenum target, GLenum pname, GLint * params);
+typedef void (GLAD_API_PTR *PFNGLGETRENDERBUFFERPARAMETERIVPROC)(GLenum target, GLenum pname, GLint * params);
+typedef void (GLAD_API_PTR *PFNGLGETSAMPLERPARAMETERIIVPROC)(GLuint sampler, GLenum pname, GLint * params);
+typedef void (GLAD_API_PTR *PFNGLGETSAMPLERPARAMETERIUIVPROC)(GLuint sampler, GLenum pname, GLuint * params);
+typedef void (GLAD_API_PTR *PFNGLGETSAMPLERPARAMETERFVPROC)(GLuint sampler, GLenum pname, GLfloat * params);
+typedef void (GLAD_API_PTR *PFNGLGETSAMPLERPARAMETERIVPROC)(GLuint sampler, GLenum pname, GLint * params);
+typedef void (GLAD_API_PTR *PFNGLGETSHADERINFOLOGPROC)(GLuint shader, GLsizei bufSize, GLsizei * length, GLchar * infoLog);
+typedef void (GLAD_API_PTR *PFNGLGETSHADERSOURCEPROC)(GLuint shader, GLsizei bufSize, GLsizei * length, GLchar * source);
+typedef void (GLAD_API_PTR *PFNGLGETSHADERIVPROC)(GLuint shader, GLenum pname, GLint * params);
+typedef const GLubyte * (GLAD_API_PTR *PFNGLGETSTRINGPROC)(GLenum name);
+typedef const GLubyte * (GLAD_API_PTR *PFNGLGETSTRINGIPROC)(GLenum name, GLuint index);
+typedef void (GLAD_API_PTR *PFNGLGETSYNCIVPROC)(GLsync sync, GLenum pname, GLsizei count, GLsizei * length, GLint * values);
+typedef void (GLAD_API_PTR *PFNGLGETTEXIMAGEPROC)(GLenum target, GLint level, GLenum format, GLenum type, void * pixels);
+typedef void (GLAD_API_PTR *PFNGLGETTEXLEVELPARAMETERFVPROC)(GLenum target, GLint level, GLenum pname, GLfloat * params);
+typedef void (GLAD_API_PTR *PFNGLGETTEXLEVELPARAMETERIVPROC)(GLenum target, GLint level, GLenum pname, GLint * params);
+typedef void (GLAD_API_PTR *PFNGLGETTEXPARAMETERIIVPROC)(GLenum target, GLenum pname, GLint * params);
+typedef void (GLAD_API_PTR *PFNGLGETTEXPARAMETERIUIVPROC)(GLenum target, GLenum pname, GLuint * params);
+typedef void (GLAD_API_PTR *PFNGLGETTEXPARAMETERFVPROC)(GLenum target, GLenum pname, GLfloat * params);
+typedef void (GLAD_API_PTR *PFNGLGETTEXPARAMETERIVPROC)(GLenum target, GLenum pname, GLint * params);
+typedef void (GLAD_API_PTR *PFNGLGETTRANSFORMFEEDBACKVARYINGPROC)(GLuint program, GLuint index, GLsizei bufSize, GLsizei * length, GLsizei * size, GLenum * type, GLchar * name);
+typedef GLuint (GLAD_API_PTR *PFNGLGETUNIFORMBLOCKINDEXPROC)(GLuint program, const GLchar * uniformBlockName);
+typedef void (GLAD_API_PTR *PFNGLGETUNIFORMINDICESPROC)(GLuint program, GLsizei uniformCount, const GLchar *const* uniformNames, GLuint * uniformIndices);
+typedef GLint (GLAD_API_PTR *PFNGLGETUNIFORMLOCATIONPROC)(GLuint program, const GLchar * name);
+typedef void (GLAD_API_PTR *PFNGLGETUNIFORMFVPROC)(GLuint program, GLint location, GLfloat * params);
+typedef void (GLAD_API_PTR *PFNGLGETUNIFORMIVPROC)(GLuint program, GLint location, GLint * params);
+typedef void (GLAD_API_PTR *PFNGLGETUNIFORMUIVPROC)(GLuint program, GLint location, GLuint * params);
+typedef void (GLAD_API_PTR *PFNGLGETVERTEXATTRIBIIVPROC)(GLuint index, GLenum pname, GLint * params);
+typedef void (GLAD_API_PTR *PFNGLGETVERTEXATTRIBIUIVPROC)(GLuint index, GLenum pname, GLuint * params);
+typedef void (GLAD_API_PTR *PFNGLGETVERTEXATTRIBPOINTERVPROC)(GLuint index, GLenum pname, void ** pointer);
+typedef void (GLAD_API_PTR *PFNGLGETVERTEXATTRIBDVPROC)(GLuint index, GLenum pname, GLdouble * params);
+typedef void (GLAD_API_PTR *PFNGLGETVERTEXATTRIBFVPROC)(GLuint index, GLenum pname, GLfloat * params);
+typedef void (GLAD_API_PTR *PFNGLGETVERTEXATTRIBIVPROC)(GLuint index, GLenum pname, GLint * params);
+typedef void (GLAD_API_PTR *PFNGLHINTPROC)(GLenum target, GLenum mode);
+typedef GLboolean (GLAD_API_PTR *PFNGLISBUFFERPROC)(GLuint buffer);
+typedef GLboolean (GLAD_API_PTR *PFNGLISENABLEDPROC)(GLenum cap);
+typedef GLboolean (GLAD_API_PTR *PFNGLISENABLEDIPROC)(GLenum target, GLuint index);
+typedef GLboolean (GLAD_API_PTR *PFNGLISFRAMEBUFFERPROC)(GLuint framebuffer);
+typedef GLboolean (GLAD_API_PTR *PFNGLISPROGRAMPROC)(GLuint program);
+typedef GLboolean (GLAD_API_PTR *PFNGLISQUERYPROC)(GLuint id);
+typedef GLboolean (GLAD_API_PTR *PFNGLISRENDERBUFFERPROC)(GLuint renderbuffer);
+typedef GLboolean (GLAD_API_PTR *PFNGLISSAMPLERPROC)(GLuint sampler);
+typedef GLboolean (GLAD_API_PTR *PFNGLISSHADERPROC)(GLuint shader);
+typedef GLboolean (GLAD_API_PTR *PFNGLISSYNCPROC)(GLsync sync);
+typedef GLboolean (GLAD_API_PTR *PFNGLISTEXTUREPROC)(GLuint texture);
+typedef GLboolean (GLAD_API_PTR *PFNGLISVERTEXARRAYPROC)(GLuint array);
+typedef void (GLAD_API_PTR *PFNGLLINEWIDTHPROC)(GLfloat width);
+typedef void (GLAD_API_PTR *PFNGLLINKPROGRAMPROC)(GLuint program);
+typedef void (GLAD_API_PTR *PFNGLLOGICOPPROC)(GLenum opcode);
+typedef void * (GLAD_API_PTR *PFNGLMAPBUFFERPROC)(GLenum target, GLenum access);
+typedef void * (GLAD_API_PTR *PFNGLMAPBUFFERRANGEPROC)(GLenum target, GLintptr offset, GLsizeiptr length, GLbitfield access);
+typedef void (GLAD_API_PTR *PFNGLMULTIDRAWARRAYSPROC)(GLenum mode, const GLint * first, const GLsizei * count, GLsizei drawcount);
+typedef void (GLAD_API_PTR *PFNGLMULTIDRAWELEMENTSPROC)(GLenum mode, const GLsizei * count, GLenum type, const void *const* indices, GLsizei drawcount);
+typedef void (GLAD_API_PTR *PFNGLMULTIDRAWELEMENTSBASEVERTEXPROC)(GLenum mode, const GLsizei * count, GLenum type, const void *const* indices, GLsizei drawcount, const GLint * basevertex);
+typedef void (GLAD_API_PTR *PFNGLPIXELSTOREFPROC)(GLenum pname, GLfloat param);
+typedef void (GLAD_API_PTR *PFNGLPIXELSTOREIPROC)(GLenum pname, GLint param);
+typedef void (GLAD_API_PTR *PFNGLPOINTPARAMETERFPROC)(GLenum pname, GLfloat param);
+typedef void (GLAD_API_PTR *PFNGLPOINTPARAMETERFVPROC)(GLenum pname, const GLfloat * params);
+typedef void (GLAD_API_PTR *PFNGLPOINTPARAMETERIPROC)(GLenum pname, GLint param);
+typedef void (GLAD_API_PTR *PFNGLPOINTPARAMETERIVPROC)(GLenum pname, const GLint * params);
+typedef void (GLAD_API_PTR *PFNGLPOINTSIZEPROC)(GLfloat size);
+typedef void (GLAD_API_PTR *PFNGLPOLYGONMODEPROC)(GLenum face, GLenum mode);
+typedef void (GLAD_API_PTR *PFNGLPOLYGONOFFSETPROC)(GLfloat factor, GLfloat units);
+typedef void (GLAD_API_PTR *PFNGLPRIMITIVERESTARTINDEXPROC)(GLuint index);
+typedef void (GLAD_API_PTR *PFNGLPROVOKINGVERTEXPROC)(GLenum mode);
+typedef void (GLAD_API_PTR *PFNGLQUERYCOUNTERPROC)(GLuint id, GLenum target);
+typedef void (GLAD_API_PTR *PFNGLREADBUFFERPROC)(GLenum src);
+typedef void (GLAD_API_PTR *PFNGLREADPIXELSPROC)(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, void * pixels);
+typedef void (GLAD_API_PTR *PFNGLRENDERBUFFERSTORAGEPROC)(GLenum target, GLenum internalformat, GLsizei width, GLsizei height);
+typedef void (GLAD_API_PTR *PFNGLRENDERBUFFERSTORAGEMULTISAMPLEPROC)(GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height);
+typedef void (GLAD_API_PTR *PFNGLSAMPLECOVERAGEPROC)(GLfloat value, GLboolean invert);
+typedef void (GLAD_API_PTR *PFNGLSAMPLEMASKIPROC)(GLuint maskNumber, GLbitfield mask);
+typedef void (GLAD_API_PTR *PFNGLSAMPLERPARAMETERIIVPROC)(GLuint sampler, GLenum pname, const GLint * param);
+typedef void (GLAD_API_PTR *PFNGLSAMPLERPARAMETERIUIVPROC)(GLuint sampler, GLenum pname, const GLuint * param);
+typedef void (GLAD_API_PTR *PFNGLSAMPLERPARAMETERFPROC)(GLuint sampler, GLenum pname, GLfloat param);
+typedef void (GLAD_API_PTR *PFNGLSAMPLERPARAMETERFVPROC)(GLuint sampler, GLenum pname, const GLfloat * param);
+typedef void (GLAD_API_PTR *PFNGLSAMPLERPARAMETERIPROC)(GLuint sampler, GLenum pname, GLint param);
+typedef void (GLAD_API_PTR *PFNGLSAMPLERPARAMETERIVPROC)(GLuint sampler, GLenum pname, const GLint * param);
+typedef void (GLAD_API_PTR *PFNGLSCISSORPROC)(GLint x, GLint y, GLsizei width, GLsizei height);
+typedef void (GLAD_API_PTR *PFNGLSHADERSOURCEPROC)(GLuint shader, GLsizei count, const GLchar *const* string, const GLint * length);
+typedef void (GLAD_API_PTR *PFNGLSTENCILFUNCPROC)(GLenum func, GLint ref, GLuint mask);
+typedef void (GLAD_API_PTR *PFNGLSTENCILFUNCSEPARATEPROC)(GLenum face, GLenum func, GLint ref, GLuint mask);
+typedef void (GLAD_API_PTR *PFNGLSTENCILMASKPROC)(GLuint mask);
+typedef void (GLAD_API_PTR *PFNGLSTENCILMASKSEPARATEPROC)(GLenum face, GLuint mask);
+typedef void (GLAD_API_PTR *PFNGLSTENCILOPPROC)(GLenum fail, GLenum zfail, GLenum zpass);
+typedef void (GLAD_API_PTR *PFNGLSTENCILOPSEPARATEPROC)(GLenum face, GLenum sfail, GLenum dpfail, GLenum dppass);
+typedef void (GLAD_API_PTR *PFNGLTEXBUFFERPROC)(GLenum target, GLenum internalformat, GLuint buffer);
+typedef void (GLAD_API_PTR *PFNGLTEXIMAGE1DPROC)(GLenum target, GLint level, GLint internalformat, GLsizei width, GLint border, GLenum format, GLenum type, const void * pixels);
+typedef void (GLAD_API_PTR *PFNGLTEXIMAGE2DPROC)(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const void * pixels);
+typedef void (GLAD_API_PTR *PFNGLTEXIMAGE2DMULTISAMPLEPROC)(GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLboolean fixedsamplelocations);
+typedef void (GLAD_API_PTR *PFNGLTEXIMAGE3DPROC)(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const void * pixels);
+typedef void (GLAD_API_PTR *PFNGLTEXIMAGE3DMULTISAMPLEPROC)(GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedsamplelocations);
+typedef void (GLAD_API_PTR *PFNGLTEXPARAMETERIIVPROC)(GLenum target, GLenum pname, const GLint * params);
+typedef void (GLAD_API_PTR *PFNGLTEXPARAMETERIUIVPROC)(GLenum target, GLenum pname, const GLuint * params);
+typedef void (GLAD_API_PTR *PFNGLTEXPARAMETERFPROC)(GLenum target, GLenum pname, GLfloat param);
+typedef void (GLAD_API_PTR *PFNGLTEXPARAMETERFVPROC)(GLenum target, GLenum pname, const GLfloat * params);
+typedef void (GLAD_API_PTR *PFNGLTEXPARAMETERIPROC)(GLenum target, GLenum pname, GLint param);
+typedef void (GLAD_API_PTR *PFNGLTEXPARAMETERIVPROC)(GLenum target, GLenum pname, const GLint * params);
+typedef void (GLAD_API_PTR *PFNGLTEXSUBIMAGE1DPROC)(GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLenum type, const void * pixels);
+typedef void (GLAD_API_PTR *PFNGLTEXSUBIMAGE2DPROC)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const void * pixels);
+typedef void (GLAD_API_PTR *PFNGLTEXSUBIMAGE3DPROC)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const void * pixels);
+typedef void (GLAD_API_PTR *PFNGLTRANSFORMFEEDBACKVARYINGSPROC)(GLuint program, GLsizei count, const GLchar *const* varyings, GLenum bufferMode);
+typedef void (GLAD_API_PTR *PFNGLUNIFORM1FPROC)(GLint location, GLfloat v0);
+typedef void (GLAD_API_PTR *PFNGLUNIFORM1FVPROC)(GLint location, GLsizei count, const GLfloat * value);
+typedef void (GLAD_API_PTR *PFNGLUNIFORM1IPROC)(GLint location, GLint v0);
+typedef void (GLAD_API_PTR *PFNGLUNIFORM1IVPROC)(GLint location, GLsizei count, const GLint * value);
+typedef void (GLAD_API_PTR *PFNGLUNIFORM1UIPROC)(GLint location, GLuint v0);
+typedef void (GLAD_API_PTR *PFNGLUNIFORM1UIVPROC)(GLint location, GLsizei count, const GLuint * value);
+typedef void (GLAD_API_PTR *PFNGLUNIFORM2FPROC)(GLint location, GLfloat v0, GLfloat v1);
+typedef void (GLAD_API_PTR *PFNGLUNIFORM2FVPROC)(GLint location, GLsizei count, const GLfloat * value);
+typedef void (GLAD_API_PTR *PFNGLUNIFORM2IPROC)(GLint location, GLint v0, GLint v1);
+typedef void (GLAD_API_PTR *PFNGLUNIFORM2IVPROC)(GLint location, GLsizei count, const GLint * value);
+typedef void (GLAD_API_PTR *PFNGLUNIFORM2UIPROC)(GLint location, GLuint v0, GLuint v1);
+typedef void (GLAD_API_PTR *PFNGLUNIFORM2UIVPROC)(GLint location, GLsizei count, const GLuint * value);
+typedef void (GLAD_API_PTR *PFNGLUNIFORM3FPROC)(GLint location, GLfloat v0, GLfloat v1, GLfloat v2);
+typedef void (GLAD_API_PTR *PFNGLUNIFORM3FVPROC)(GLint location, GLsizei count, const GLfloat * value);
+typedef void (GLAD_API_PTR *PFNGLUNIFORM3IPROC)(GLint location, GLint v0, GLint v1, GLint v2);
+typedef void (GLAD_API_PTR *PFNGLUNIFORM3IVPROC)(GLint location, GLsizei count, const GLint * value);
+typedef void (GLAD_API_PTR *PFNGLUNIFORM3UIPROC)(GLint location, GLuint v0, GLuint v1, GLuint v2);
+typedef void (GLAD_API_PTR *PFNGLUNIFORM3UIVPROC)(GLint location, GLsizei count, const GLuint * value);
+typedef void (GLAD_API_PTR *PFNGLUNIFORM4FPROC)(GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3);
+typedef void (GLAD_API_PTR *PFNGLUNIFORM4FVPROC)(GLint location, GLsizei count, const GLfloat * value);
+typedef void (GLAD_API_PTR *PFNGLUNIFORM4IPROC)(GLint location, GLint v0, GLint v1, GLint v2, GLint v3);
+typedef void (GLAD_API_PTR *PFNGLUNIFORM4IVPROC)(GLint location, GLsizei count, const GLint * value);
+typedef void (GLAD_API_PTR *PFNGLUNIFORM4UIPROC)(GLint location, GLuint v0, GLuint v1, GLuint v2, GLuint v3);
+typedef void (GLAD_API_PTR *PFNGLUNIFORM4UIVPROC)(GLint location, GLsizei count, const GLuint * value);
+typedef void (GLAD_API_PTR *PFNGLUNIFORMBLOCKBINDINGPROC)(GLuint program, GLuint uniformBlockIndex, GLuint uniformBlockBinding);
+typedef void (GLAD_API_PTR *PFNGLUNIFORMMATRIX2FVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLfloat * value);
+typedef void (GLAD_API_PTR *PFNGLUNIFORMMATRIX2X3FVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLfloat * value);
+typedef void (GLAD_API_PTR *PFNGLUNIFORMMATRIX2X4FVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLfloat * value);
+typedef void (GLAD_API_PTR *PFNGLUNIFORMMATRIX3FVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLfloat * value);
+typedef void (GLAD_API_PTR *PFNGLUNIFORMMATRIX3X2FVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLfloat * value);
+typedef void (GLAD_API_PTR *PFNGLUNIFORMMATRIX3X4FVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLfloat * value);
+typedef void (GLAD_API_PTR *PFNGLUNIFORMMATRIX4FVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLfloat * value);
+typedef void (GLAD_API_PTR *PFNGLUNIFORMMATRIX4X2FVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLfloat * value);
+typedef void (GLAD_API_PTR *PFNGLUNIFORMMATRIX4X3FVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLfloat * value);
+typedef GLboolean (GLAD_API_PTR *PFNGLUNMAPBUFFERPROC)(GLenum target);
+typedef void (GLAD_API_PTR *PFNGLUSEPROGRAMPROC)(GLuint program);
+typedef void (GLAD_API_PTR *PFNGLVALIDATEPROGRAMPROC)(GLuint program);
+typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB1DPROC)(GLuint index, GLdouble x);
+typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB1DVPROC)(GLuint index, const GLdouble * v);
+typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB1FPROC)(GLuint index, GLfloat x);
+typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB1FVPROC)(GLuint index, const GLfloat * v);
+typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB1SPROC)(GLuint index, GLshort x);
+typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB1SVPROC)(GLuint index, const GLshort * v);
+typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB2DPROC)(GLuint index, GLdouble x, GLdouble y);
+typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB2DVPROC)(GLuint index, const GLdouble * v);
+typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB2FPROC)(GLuint index, GLfloat x, GLfloat y);
+typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB2FVPROC)(GLuint index, const GLfloat * v);
+typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB2SPROC)(GLuint index, GLshort x, GLshort y);
+typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB2SVPROC)(GLuint index, const GLshort * v);
+typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB3DPROC)(GLuint index, GLdouble x, GLdouble y, GLdouble z);
+typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB3DVPROC)(GLuint index, const GLdouble * v);
+typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB3FPROC)(GLuint index, GLfloat x, GLfloat y, GLfloat z);
+typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB3FVPROC)(GLuint index, const GLfloat * v);
+typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB3SPROC)(GLuint index, GLshort x, GLshort y, GLshort z);
+typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB3SVPROC)(GLuint index, const GLshort * v);
+typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB4NBVPROC)(GLuint index, const GLbyte * v);
+typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB4NIVPROC)(GLuint index, const GLint * v);
+typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB4NSVPROC)(GLuint index, const GLshort * v);
+typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB4NUBPROC)(GLuint index, GLubyte x, GLubyte y, GLubyte z, GLubyte w);
+typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB4NUBVPROC)(GLuint index, const GLubyte * v);
+typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB4NUIVPROC)(GLuint index, const GLuint * v);
+typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB4NUSVPROC)(GLuint index, const GLushort * v);
+typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB4BVPROC)(GLuint index, const GLbyte * v);
+typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB4DPROC)(GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w);
+typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB4DVPROC)(GLuint index, const GLdouble * v);
+typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB4FPROC)(GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w);
+typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB4FVPROC)(GLuint index, const GLfloat * v);
+typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB4IVPROC)(GLuint index, const GLint * v);
+typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB4SPROC)(GLuint index, GLshort x, GLshort y, GLshort z, GLshort w);
+typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB4SVPROC)(GLuint index, const GLshort * v);
+typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB4UBVPROC)(GLuint index, const GLubyte * v);
+typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB4UIVPROC)(GLuint index, const GLuint * v);
+typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB4USVPROC)(GLuint index, const GLushort * v);
+typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBDIVISORPROC)(GLuint index, GLuint divisor);
+typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBI1IPROC)(GLuint index, GLint x);
+typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBI1IVPROC)(GLuint index, const GLint * v);
+typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBI1UIPROC)(GLuint index, GLuint x);
+typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBI1UIVPROC)(GLuint index, const GLuint * v);
+typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBI2IPROC)(GLuint index, GLint x, GLint y);
+typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBI2IVPROC)(GLuint index, const GLint * v);
+typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBI2UIPROC)(GLuint index, GLuint x, GLuint y);
+typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBI2UIVPROC)(GLuint index, const GLuint * v);
+typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBI3IPROC)(GLuint index, GLint x, GLint y, GLint z);
+typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBI3IVPROC)(GLuint index, const GLint * v);
+typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBI3UIPROC)(GLuint index, GLuint x, GLuint y, GLuint z);
+typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBI3UIVPROC)(GLuint index, const GLuint * v);
+typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBI4BVPROC)(GLuint index, const GLbyte * v);
+typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBI4IPROC)(GLuint index, GLint x, GLint y, GLint z, GLint w);
+typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBI4IVPROC)(GLuint index, const GLint * v);
+typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBI4SVPROC)(GLuint index, const GLshort * v);
+typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBI4UBVPROC)(GLuint index, const GLubyte * v);
+typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBI4UIPROC)(GLuint index, GLuint x, GLuint y, GLuint z, GLuint w);
+typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBI4UIVPROC)(GLuint index, const GLuint * v);
+typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBI4USVPROC)(GLuint index, const GLushort * v);
+typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBIPOINTERPROC)(GLuint index, GLint size, GLenum type, GLsizei stride, const void * pointer);
+typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBP1UIPROC)(GLuint index, GLenum type, GLboolean normalized, GLuint value);
+typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBP1UIVPROC)(GLuint index, GLenum type, GLboolean normalized, const GLuint * value);
+typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBP2UIPROC)(GLuint index, GLenum type, GLboolean normalized, GLuint value);
+typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBP2UIVPROC)(GLuint index, GLenum type, GLboolean normalized, const GLuint * value);
+typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBP3UIPROC)(GLuint index, GLenum type, GLboolean normalized, GLuint value);
+typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBP3UIVPROC)(GLuint index, GLenum type, GLboolean normalized, const GLuint * value);
+typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBP4UIPROC)(GLuint index, GLenum type, GLboolean normalized, GLuint value);
+typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBP4UIVPROC)(GLuint index, GLenum type, GLboolean normalized, const GLuint * value);
+typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBPOINTERPROC)(GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const void * pointer);
+typedef void (GLAD_API_PTR *PFNGLVIEWPORTPROC)(GLint x, GLint y, GLsizei width, GLsizei height);
+typedef void (GLAD_API_PTR *PFNGLWAITSYNCPROC)(GLsync sync, GLbitfield flags, GLuint64 timeout);
+
+GLAD_API_CALL PFNGLACTIVETEXTUREPROC glad_glActiveTexture;
+#define glActiveTexture glad_glActiveTexture
+GLAD_API_CALL PFNGLATTACHSHADERPROC glad_glAttachShader;
+#define glAttachShader glad_glAttachShader
+GLAD_API_CALL PFNGLBEGINCONDITIONALRENDERPROC glad_glBeginConditionalRender;
+#define glBeginConditionalRender glad_glBeginConditionalRender
+GLAD_API_CALL PFNGLBEGINQUERYPROC glad_glBeginQuery;
+#define glBeginQuery glad_glBeginQuery
+GLAD_API_CALL PFNGLBEGINTRANSFORMFEEDBACKPROC glad_glBeginTransformFeedback;
+#define glBeginTransformFeedback glad_glBeginTransformFeedback
+GLAD_API_CALL PFNGLBINDATTRIBLOCATIONPROC glad_glBindAttribLocation;
+#define glBindAttribLocation glad_glBindAttribLocation
+GLAD_API_CALL PFNGLBINDBUFFERPROC glad_glBindBuffer;
+#define glBindBuffer glad_glBindBuffer
+GLAD_API_CALL PFNGLBINDBUFFERBASEPROC glad_glBindBufferBase;
+#define glBindBufferBase glad_glBindBufferBase
+GLAD_API_CALL PFNGLBINDBUFFERRANGEPROC glad_glBindBufferRange;
+#define glBindBufferRange glad_glBindBufferRange
+GLAD_API_CALL PFNGLBINDFRAGDATALOCATIONPROC glad_glBindFragDataLocation;
+#define glBindFragDataLocation glad_glBindFragDataLocation
+GLAD_API_CALL PFNGLBINDFRAGDATALOCATIONINDEXEDPROC glad_glBindFragDataLocationIndexed;
+#define glBindFragDataLocationIndexed glad_glBindFragDataLocationIndexed
+GLAD_API_CALL PFNGLBINDFRAMEBUFFERPROC glad_glBindFramebuffer;
+#define glBindFramebuffer glad_glBindFramebuffer
+GLAD_API_CALL PFNGLBINDRENDERBUFFERPROC glad_glBindRenderbuffer;
+#define glBindRenderbuffer glad_glBindRenderbuffer
+GLAD_API_CALL PFNGLBINDSAMPLERPROC glad_glBindSampler;
+#define glBindSampler glad_glBindSampler
+GLAD_API_CALL PFNGLBINDTEXTUREPROC glad_glBindTexture;
+#define glBindTexture glad_glBindTexture
+GLAD_API_CALL PFNGLBINDVERTEXARRAYPROC glad_glBindVertexArray;
+#define glBindVertexArray glad_glBindVertexArray
+GLAD_API_CALL PFNGLBLENDCOLORPROC glad_glBlendColor;
+#define glBlendColor glad_glBlendColor
+GLAD_API_CALL PFNGLBLENDEQUATIONPROC glad_glBlendEquation;
+#define glBlendEquation glad_glBlendEquation
+GLAD_API_CALL PFNGLBLENDEQUATIONSEPARATEPROC glad_glBlendEquationSeparate;
+#define glBlendEquationSeparate glad_glBlendEquationSeparate
+GLAD_API_CALL PFNGLBLENDFUNCPROC glad_glBlendFunc;
+#define glBlendFunc glad_glBlendFunc
+GLAD_API_CALL PFNGLBLENDFUNCSEPARATEPROC glad_glBlendFuncSeparate;
+#define glBlendFuncSeparate glad_glBlendFuncSeparate
+GLAD_API_CALL PFNGLBLITFRAMEBUFFERPROC glad_glBlitFramebuffer;
+#define glBlitFramebuffer glad_glBlitFramebuffer
+GLAD_API_CALL PFNGLBUFFERDATAPROC glad_glBufferData;
+#define glBufferData glad_glBufferData
+GLAD_API_CALL PFNGLBUFFERSUBDATAPROC glad_glBufferSubData;
+#define glBufferSubData glad_glBufferSubData
+GLAD_API_CALL PFNGLCHECKFRAMEBUFFERSTATUSPROC glad_glCheckFramebufferStatus;
+#define glCheckFramebufferStatus glad_glCheckFramebufferStatus
+GLAD_API_CALL PFNGLCLAMPCOLORPROC glad_glClampColor;
+#define glClampColor glad_glClampColor
+GLAD_API_CALL PFNGLCLEARPROC glad_glClear;
+#define glClear glad_glClear
+GLAD_API_CALL PFNGLCLEARBUFFERFIPROC glad_glClearBufferfi;
+#define glClearBufferfi glad_glClearBufferfi
+GLAD_API_CALL PFNGLCLEARBUFFERFVPROC glad_glClearBufferfv;
+#define glClearBufferfv glad_glClearBufferfv
+GLAD_API_CALL PFNGLCLEARBUFFERIVPROC glad_glClearBufferiv;
+#define glClearBufferiv glad_glClearBufferiv
+GLAD_API_CALL PFNGLCLEARBUFFERUIVPROC glad_glClearBufferuiv;
+#define glClearBufferuiv glad_glClearBufferuiv
+GLAD_API_CALL PFNGLCLEARCOLORPROC glad_glClearColor;
+#define glClearColor glad_glClearColor
+GLAD_API_CALL PFNGLCLEARDEPTHPROC glad_glClearDepth;
+#define glClearDepth glad_glClearDepth
+GLAD_API_CALL PFNGLCLEARSTENCILPROC glad_glClearStencil;
+#define glClearStencil glad_glClearStencil
+GLAD_API_CALL PFNGLCLIENTWAITSYNCPROC glad_glClientWaitSync;
+#define glClientWaitSync glad_glClientWaitSync
+GLAD_API_CALL PFNGLCOLORMASKPROC glad_glColorMask;
+#define glColorMask glad_glColorMask
+GLAD_API_CALL PFNGLCOLORMASKIPROC glad_glColorMaski;
+#define glColorMaski glad_glColorMaski
+GLAD_API_CALL PFNGLCOMPILESHADERPROC glad_glCompileShader;
+#define glCompileShader glad_glCompileShader
+GLAD_API_CALL PFNGLCOMPRESSEDTEXIMAGE1DPROC glad_glCompressedTexImage1D;
+#define glCompressedTexImage1D glad_glCompressedTexImage1D
+GLAD_API_CALL PFNGLCOMPRESSEDTEXIMAGE2DPROC glad_glCompressedTexImage2D;
+#define glCompressedTexImage2D glad_glCompressedTexImage2D
+GLAD_API_CALL PFNGLCOMPRESSEDTEXIMAGE3DPROC glad_glCompressedTexImage3D;
+#define glCompressedTexImage3D glad_glCompressedTexImage3D
+GLAD_API_CALL PFNGLCOMPRESSEDTEXSUBIMAGE1DPROC glad_glCompressedTexSubImage1D;
+#define glCompressedTexSubImage1D glad_glCompressedTexSubImage1D
+GLAD_API_CALL PFNGLCOMPRESSEDTEXSUBIMAGE2DPROC glad_glCompressedTexSubImage2D;
+#define glCompressedTexSubImage2D glad_glCompressedTexSubImage2D
+GLAD_API_CALL PFNGLCOMPRESSEDTEXSUBIMAGE3DPROC glad_glCompressedTexSubImage3D;
+#define glCompressedTexSubImage3D glad_glCompressedTexSubImage3D
+GLAD_API_CALL PFNGLCOPYBUFFERSUBDATAPROC glad_glCopyBufferSubData;
+#define glCopyBufferSubData glad_glCopyBufferSubData
+GLAD_API_CALL PFNGLCOPYTEXIMAGE1DPROC glad_glCopyTexImage1D;
+#define glCopyTexImage1D glad_glCopyTexImage1D
+GLAD_API_CALL PFNGLCOPYTEXIMAGE2DPROC glad_glCopyTexImage2D;
+#define glCopyTexImage2D glad_glCopyTexImage2D
+GLAD_API_CALL PFNGLCOPYTEXSUBIMAGE1DPROC glad_glCopyTexSubImage1D;
+#define glCopyTexSubImage1D glad_glCopyTexSubImage1D
+GLAD_API_CALL PFNGLCOPYTEXSUBIMAGE2DPROC glad_glCopyTexSubImage2D;
+#define glCopyTexSubImage2D glad_glCopyTexSubImage2D
+GLAD_API_CALL PFNGLCOPYTEXSUBIMAGE3DPROC glad_glCopyTexSubImage3D;
+#define glCopyTexSubImage3D glad_glCopyTexSubImage3D
+GLAD_API_CALL PFNGLCREATEPROGRAMPROC glad_glCreateProgram;
+#define glCreateProgram glad_glCreateProgram
+GLAD_API_CALL PFNGLCREATESHADERPROC glad_glCreateShader;
+#define glCreateShader glad_glCreateShader
+GLAD_API_CALL PFNGLCULLFACEPROC glad_glCullFace;
+#define glCullFace glad_glCullFace
+GLAD_API_CALL PFNGLDELETEBUFFERSPROC glad_glDeleteBuffers;
+#define glDeleteBuffers glad_glDeleteBuffers
+GLAD_API_CALL PFNGLDELETEFRAMEBUFFERSPROC glad_glDeleteFramebuffers;
+#define glDeleteFramebuffers glad_glDeleteFramebuffers
+GLAD_API_CALL PFNGLDELETEPROGRAMPROC glad_glDeleteProgram;
+#define glDeleteProgram glad_glDeleteProgram
+GLAD_API_CALL PFNGLDELETEQUERIESPROC glad_glDeleteQueries;
+#define glDeleteQueries glad_glDeleteQueries
+GLAD_API_CALL PFNGLDELETERENDERBUFFERSPROC glad_glDeleteRenderbuffers;
+#define glDeleteRenderbuffers glad_glDeleteRenderbuffers
+GLAD_API_CALL PFNGLDELETESAMPLERSPROC glad_glDeleteSamplers;
+#define glDeleteSamplers glad_glDeleteSamplers
+GLAD_API_CALL PFNGLDELETESHADERPROC glad_glDeleteShader;
+#define glDeleteShader glad_glDeleteShader
+GLAD_API_CALL PFNGLDELETESYNCPROC glad_glDeleteSync;
+#define glDeleteSync glad_glDeleteSync
+GLAD_API_CALL PFNGLDELETETEXTURESPROC glad_glDeleteTextures;
+#define glDeleteTextures glad_glDeleteTextures
+GLAD_API_CALL PFNGLDELETEVERTEXARRAYSPROC glad_glDeleteVertexArrays;
+#define glDeleteVertexArrays glad_glDeleteVertexArrays
+GLAD_API_CALL PFNGLDEPTHFUNCPROC glad_glDepthFunc;
+#define glDepthFunc glad_glDepthFunc
+GLAD_API_CALL PFNGLDEPTHMASKPROC glad_glDepthMask;
+#define glDepthMask glad_glDepthMask
+GLAD_API_CALL PFNGLDEPTHRANGEPROC glad_glDepthRange;
+#define glDepthRange glad_glDepthRange
+GLAD_API_CALL PFNGLDETACHSHADERPROC glad_glDetachShader;
+#define glDetachShader glad_glDetachShader
+GLAD_API_CALL PFNGLDISABLEPROC glad_glDisable;
+#define glDisable glad_glDisable
+GLAD_API_CALL PFNGLDISABLEVERTEXATTRIBARRAYPROC glad_glDisableVertexAttribArray;
+#define glDisableVertexAttribArray glad_glDisableVertexAttribArray
+GLAD_API_CALL PFNGLDISABLEIPROC glad_glDisablei;
+#define glDisablei glad_glDisablei
+GLAD_API_CALL PFNGLDRAWARRAYSPROC glad_glDrawArrays;
+#define glDrawArrays glad_glDrawArrays
+GLAD_API_CALL PFNGLDRAWARRAYSINSTANCEDPROC glad_glDrawArraysInstanced;
+#define glDrawArraysInstanced glad_glDrawArraysInstanced
+GLAD_API_CALL PFNGLDRAWBUFFERPROC glad_glDrawBuffer;
+#define glDrawBuffer glad_glDrawBuffer
+GLAD_API_CALL PFNGLDRAWBUFFERSPROC glad_glDrawBuffers;
+#define glDrawBuffers glad_glDrawBuffers
+GLAD_API_CALL PFNGLDRAWELEMENTSPROC glad_glDrawElements;
+#define glDrawElements glad_glDrawElements
+GLAD_API_CALL PFNGLDRAWELEMENTSBASEVERTEXPROC glad_glDrawElementsBaseVertex;
+#define glDrawElementsBaseVertex glad_glDrawElementsBaseVertex
+GLAD_API_CALL PFNGLDRAWELEMENTSINSTANCEDPROC glad_glDrawElementsInstanced;
+#define glDrawElementsInstanced glad_glDrawElementsInstanced
+GLAD_API_CALL PFNGLDRAWELEMENTSINSTANCEDBASEVERTEXPROC glad_glDrawElementsInstancedBaseVertex;
+#define glDrawElementsInstancedBaseVertex glad_glDrawElementsInstancedBaseVertex
+GLAD_API_CALL PFNGLDRAWRANGEELEMENTSPROC glad_glDrawRangeElements;
+#define glDrawRangeElements glad_glDrawRangeElements
+GLAD_API_CALL PFNGLDRAWRANGEELEMENTSBASEVERTEXPROC glad_glDrawRangeElementsBaseVertex;
+#define glDrawRangeElementsBaseVertex glad_glDrawRangeElementsBaseVertex
+GLAD_API_CALL PFNGLENABLEPROC glad_glEnable;
+#define glEnable glad_glEnable
+GLAD_API_CALL PFNGLENABLEVERTEXATTRIBARRAYPROC glad_glEnableVertexAttribArray;
+#define glEnableVertexAttribArray glad_glEnableVertexAttribArray
+GLAD_API_CALL PFNGLENABLEIPROC glad_glEnablei;
+#define glEnablei glad_glEnablei
+GLAD_API_CALL PFNGLENDCONDITIONALRENDERPROC glad_glEndConditionalRender;
+#define glEndConditionalRender glad_glEndConditionalRender
+GLAD_API_CALL PFNGLENDQUERYPROC glad_glEndQuery;
+#define glEndQuery glad_glEndQuery
+GLAD_API_CALL PFNGLENDTRANSFORMFEEDBACKPROC glad_glEndTransformFeedback;
+#define glEndTransformFeedback glad_glEndTransformFeedback
+GLAD_API_CALL PFNGLFENCESYNCPROC glad_glFenceSync;
+#define glFenceSync glad_glFenceSync
+GLAD_API_CALL PFNGLFINISHPROC glad_glFinish;
+#define glFinish glad_glFinish
+GLAD_API_CALL PFNGLFLUSHPROC glad_glFlush;
+#define glFlush glad_glFlush
+GLAD_API_CALL PFNGLFLUSHMAPPEDBUFFERRANGEPROC glad_glFlushMappedBufferRange;
+#define glFlushMappedBufferRange glad_glFlushMappedBufferRange
+GLAD_API_CALL PFNGLFRAMEBUFFERRENDERBUFFERPROC glad_glFramebufferRenderbuffer;
+#define glFramebufferRenderbuffer glad_glFramebufferRenderbuffer
+GLAD_API_CALL PFNGLFRAMEBUFFERTEXTUREPROC glad_glFramebufferTexture;
+#define glFramebufferTexture glad_glFramebufferTexture
+GLAD_API_CALL PFNGLFRAMEBUFFERTEXTURE1DPROC glad_glFramebufferTexture1D;
+#define glFramebufferTexture1D glad_glFramebufferTexture1D
+GLAD_API_CALL PFNGLFRAMEBUFFERTEXTURE2DPROC glad_glFramebufferTexture2D;
+#define glFramebufferTexture2D glad_glFramebufferTexture2D
+GLAD_API_CALL PFNGLFRAMEBUFFERTEXTURE3DPROC glad_glFramebufferTexture3D;
+#define glFramebufferTexture3D glad_glFramebufferTexture3D
+GLAD_API_CALL PFNGLFRAMEBUFFERTEXTURELAYERPROC glad_glFramebufferTextureLayer;
+#define glFramebufferTextureLayer glad_glFramebufferTextureLayer
+GLAD_API_CALL PFNGLFRONTFACEPROC glad_glFrontFace;
+#define glFrontFace glad_glFrontFace
+GLAD_API_CALL PFNGLGENBUFFERSPROC glad_glGenBuffers;
+#define glGenBuffers glad_glGenBuffers
+GLAD_API_CALL PFNGLGENFRAMEBUFFERSPROC glad_glGenFramebuffers;
+#define glGenFramebuffers glad_glGenFramebuffers
+GLAD_API_CALL PFNGLGENQUERIESPROC glad_glGenQueries;
+#define glGenQueries glad_glGenQueries
+GLAD_API_CALL PFNGLGENRENDERBUFFERSPROC glad_glGenRenderbuffers;
+#define glGenRenderbuffers glad_glGenRenderbuffers
+GLAD_API_CALL PFNGLGENSAMPLERSPROC glad_glGenSamplers;
+#define glGenSamplers glad_glGenSamplers
+GLAD_API_CALL PFNGLGENTEXTURESPROC glad_glGenTextures;
+#define glGenTextures glad_glGenTextures
+GLAD_API_CALL PFNGLGENVERTEXARRAYSPROC glad_glGenVertexArrays;
+#define glGenVertexArrays glad_glGenVertexArrays
+GLAD_API_CALL PFNGLGENERATEMIPMAPPROC glad_glGenerateMipmap;
+#define glGenerateMipmap glad_glGenerateMipmap
+GLAD_API_CALL PFNGLGETACTIVEATTRIBPROC glad_glGetActiveAttrib;
+#define glGetActiveAttrib glad_glGetActiveAttrib
+GLAD_API_CALL PFNGLGETACTIVEUNIFORMPROC glad_glGetActiveUniform;
+#define glGetActiveUniform glad_glGetActiveUniform
+GLAD_API_CALL PFNGLGETACTIVEUNIFORMBLOCKNAMEPROC glad_glGetActiveUniformBlockName;
+#define glGetActiveUniformBlockName glad_glGetActiveUniformBlockName
+GLAD_API_CALL PFNGLGETACTIVEUNIFORMBLOCKIVPROC glad_glGetActiveUniformBlockiv;
+#define glGetActiveUniformBlockiv glad_glGetActiveUniformBlockiv
+GLAD_API_CALL PFNGLGETACTIVEUNIFORMNAMEPROC glad_glGetActiveUniformName;
+#define glGetActiveUniformName glad_glGetActiveUniformName
+GLAD_API_CALL PFNGLGETACTIVEUNIFORMSIVPROC glad_glGetActiveUniformsiv;
+#define glGetActiveUniformsiv glad_glGetActiveUniformsiv
+GLAD_API_CALL PFNGLGETATTACHEDSHADERSPROC glad_glGetAttachedShaders;
+#define glGetAttachedShaders glad_glGetAttachedShaders
+GLAD_API_CALL PFNGLGETATTRIBLOCATIONPROC glad_glGetAttribLocation;
+#define glGetAttribLocation glad_glGetAttribLocation
+GLAD_API_CALL PFNGLGETBOOLEANI_VPROC glad_glGetBooleani_v;
+#define glGetBooleani_v glad_glGetBooleani_v
+GLAD_API_CALL PFNGLGETBOOLEANVPROC glad_glGetBooleanv;
+#define glGetBooleanv glad_glGetBooleanv
+GLAD_API_CALL PFNGLGETBUFFERPARAMETERI64VPROC glad_glGetBufferParameteri64v;
+#define glGetBufferParameteri64v glad_glGetBufferParameteri64v
+GLAD_API_CALL PFNGLGETBUFFERPARAMETERIVPROC glad_glGetBufferParameteriv;
+#define glGetBufferParameteriv glad_glGetBufferParameteriv
+GLAD_API_CALL PFNGLGETBUFFERPOINTERVPROC glad_glGetBufferPointerv;
+#define glGetBufferPointerv glad_glGetBufferPointerv
+GLAD_API_CALL PFNGLGETBUFFERSUBDATAPROC glad_glGetBufferSubData;
+#define glGetBufferSubData glad_glGetBufferSubData
+GLAD_API_CALL PFNGLGETCOMPRESSEDTEXIMAGEPROC glad_glGetCompressedTexImage;
+#define glGetCompressedTexImage glad_glGetCompressedTexImage
+GLAD_API_CALL PFNGLGETDOUBLEVPROC glad_glGetDoublev;
+#define glGetDoublev glad_glGetDoublev
+GLAD_API_CALL PFNGLGETERRORPROC glad_glGetError;
+#define glGetError glad_glGetError
+GLAD_API_CALL PFNGLGETFLOATVPROC glad_glGetFloatv;
+#define glGetFloatv glad_glGetFloatv
+GLAD_API_CALL PFNGLGETFRAGDATAINDEXPROC glad_glGetFragDataIndex;
+#define glGetFragDataIndex glad_glGetFragDataIndex
+GLAD_API_CALL PFNGLGETFRAGDATALOCATIONPROC glad_glGetFragDataLocation;
+#define glGetFragDataLocation glad_glGetFragDataLocation
+GLAD_API_CALL PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVPROC glad_glGetFramebufferAttachmentParameteriv;
+#define glGetFramebufferAttachmentParameteriv glad_glGetFramebufferAttachmentParameteriv
+GLAD_API_CALL PFNGLGETINTEGER64I_VPROC glad_glGetInteger64i_v;
+#define glGetInteger64i_v glad_glGetInteger64i_v
+GLAD_API_CALL PFNGLGETINTEGER64VPROC glad_glGetInteger64v;
+#define glGetInteger64v glad_glGetInteger64v
+GLAD_API_CALL PFNGLGETINTEGERI_VPROC glad_glGetIntegeri_v;
+#define glGetIntegeri_v glad_glGetIntegeri_v
+GLAD_API_CALL PFNGLGETINTEGERVPROC glad_glGetIntegerv;
+#define glGetIntegerv glad_glGetIntegerv
+GLAD_API_CALL PFNGLGETMULTISAMPLEFVPROC glad_glGetMultisamplefv;
+#define glGetMultisamplefv glad_glGetMultisamplefv
+GLAD_API_CALL PFNGLGETPROGRAMINFOLOGPROC glad_glGetProgramInfoLog;
+#define glGetProgramInfoLog glad_glGetProgramInfoLog
+GLAD_API_CALL PFNGLGETPROGRAMIVPROC glad_glGetProgramiv;
+#define glGetProgramiv glad_glGetProgramiv
+GLAD_API_CALL PFNGLGETQUERYOBJECTI64VPROC glad_glGetQueryObjecti64v;
+#define glGetQueryObjecti64v glad_glGetQueryObjecti64v
+GLAD_API_CALL PFNGLGETQUERYOBJECTIVPROC glad_glGetQueryObjectiv;
+#define glGetQueryObjectiv glad_glGetQueryObjectiv
+GLAD_API_CALL PFNGLGETQUERYOBJECTUI64VPROC glad_glGetQueryObjectui64v;
+#define glGetQueryObjectui64v glad_glGetQueryObjectui64v
+GLAD_API_CALL PFNGLGETQUERYOBJECTUIVPROC glad_glGetQueryObjectuiv;
+#define glGetQueryObjectuiv glad_glGetQueryObjectuiv
+GLAD_API_CALL PFNGLGETQUERYIVPROC glad_glGetQueryiv;
+#define glGetQueryiv glad_glGetQueryiv
+GLAD_API_CALL PFNGLGETRENDERBUFFERPARAMETERIVPROC glad_glGetRenderbufferParameteriv;
+#define glGetRenderbufferParameteriv glad_glGetRenderbufferParameteriv
+GLAD_API_CALL PFNGLGETSAMPLERPARAMETERIIVPROC glad_glGetSamplerParameterIiv;
+#define glGetSamplerParameterIiv glad_glGetSamplerParameterIiv
+GLAD_API_CALL PFNGLGETSAMPLERPARAMETERIUIVPROC glad_glGetSamplerParameterIuiv;
+#define glGetSamplerParameterIuiv glad_glGetSamplerParameterIuiv
+GLAD_API_CALL PFNGLGETSAMPLERPARAMETERFVPROC glad_glGetSamplerParameterfv;
+#define glGetSamplerParameterfv glad_glGetSamplerParameterfv
+GLAD_API_CALL PFNGLGETSAMPLERPARAMETERIVPROC glad_glGetSamplerParameteriv;
+#define glGetSamplerParameteriv glad_glGetSamplerParameteriv
+GLAD_API_CALL PFNGLGETSHADERINFOLOGPROC glad_glGetShaderInfoLog;
+#define glGetShaderInfoLog glad_glGetShaderInfoLog
+GLAD_API_CALL PFNGLGETSHADERSOURCEPROC glad_glGetShaderSource;
+#define glGetShaderSource glad_glGetShaderSource
+GLAD_API_CALL PFNGLGETSHADERIVPROC glad_glGetShaderiv;
+#define glGetShaderiv glad_glGetShaderiv
+GLAD_API_CALL PFNGLGETSTRINGPROC glad_glGetString;
+#define glGetString glad_glGetString
+GLAD_API_CALL PFNGLGETSTRINGIPROC glad_glGetStringi;
+#define glGetStringi glad_glGetStringi
+GLAD_API_CALL PFNGLGETSYNCIVPROC glad_glGetSynciv;
+#define glGetSynciv glad_glGetSynciv
+GLAD_API_CALL PFNGLGETTEXIMAGEPROC glad_glGetTexImage;
+#define glGetTexImage glad_glGetTexImage
+GLAD_API_CALL PFNGLGETTEXLEVELPARAMETERFVPROC glad_glGetTexLevelParameterfv;
+#define glGetTexLevelParameterfv glad_glGetTexLevelParameterfv
+GLAD_API_CALL PFNGLGETTEXLEVELPARAMETERIVPROC glad_glGetTexLevelParameteriv;
+#define glGetTexLevelParameteriv glad_glGetTexLevelParameteriv
+GLAD_API_CALL PFNGLGETTEXPARAMETERIIVPROC glad_glGetTexParameterIiv;
+#define glGetTexParameterIiv glad_glGetTexParameterIiv
+GLAD_API_CALL PFNGLGETTEXPARAMETERIUIVPROC glad_glGetTexParameterIuiv;
+#define glGetTexParameterIuiv glad_glGetTexParameterIuiv
+GLAD_API_CALL PFNGLGETTEXPARAMETERFVPROC glad_glGetTexParameterfv;
+#define glGetTexParameterfv glad_glGetTexParameterfv
+GLAD_API_CALL PFNGLGETTEXPARAMETERIVPROC glad_glGetTexParameteriv;
+#define glGetTexParameteriv glad_glGetTexParameteriv
+GLAD_API_CALL PFNGLGETTRANSFORMFEEDBACKVARYINGPROC glad_glGetTransformFeedbackVarying;
+#define glGetTransformFeedbackVarying glad_glGetTransformFeedbackVarying
+GLAD_API_CALL PFNGLGETUNIFORMBLOCKINDEXPROC glad_glGetUniformBlockIndex;
+#define glGetUniformBlockIndex glad_glGetUniformBlockIndex
+GLAD_API_CALL PFNGLGETUNIFORMINDICESPROC glad_glGetUniformIndices;
+#define glGetUniformIndices glad_glGetUniformIndices
+GLAD_API_CALL PFNGLGETUNIFORMLOCATIONPROC glad_glGetUniformLocation;
+#define glGetUniformLocation glad_glGetUniformLocation
+GLAD_API_CALL PFNGLGETUNIFORMFVPROC glad_glGetUniformfv;
+#define glGetUniformfv glad_glGetUniformfv
+GLAD_API_CALL PFNGLGETUNIFORMIVPROC glad_glGetUniformiv;
+#define glGetUniformiv glad_glGetUniformiv
+GLAD_API_CALL PFNGLGETUNIFORMUIVPROC glad_glGetUniformuiv;
+#define glGetUniformuiv glad_glGetUniformuiv
+GLAD_API_CALL PFNGLGETVERTEXATTRIBIIVPROC glad_glGetVertexAttribIiv;
+#define glGetVertexAttribIiv glad_glGetVertexAttribIiv
+GLAD_API_CALL PFNGLGETVERTEXATTRIBIUIVPROC glad_glGetVertexAttribIuiv;
+#define glGetVertexAttribIuiv glad_glGetVertexAttribIuiv
+GLAD_API_CALL PFNGLGETVERTEXATTRIBPOINTERVPROC glad_glGetVertexAttribPointerv;
+#define glGetVertexAttribPointerv glad_glGetVertexAttribPointerv
+GLAD_API_CALL PFNGLGETVERTEXATTRIBDVPROC glad_glGetVertexAttribdv;
+#define glGetVertexAttribdv glad_glGetVertexAttribdv
+GLAD_API_CALL PFNGLGETVERTEXATTRIBFVPROC glad_glGetVertexAttribfv;
+#define glGetVertexAttribfv glad_glGetVertexAttribfv
+GLAD_API_CALL PFNGLGETVERTEXATTRIBIVPROC glad_glGetVertexAttribiv;
+#define glGetVertexAttribiv glad_glGetVertexAttribiv
+GLAD_API_CALL PFNGLHINTPROC glad_glHint;
+#define glHint glad_glHint
+GLAD_API_CALL PFNGLISBUFFERPROC glad_glIsBuffer;
+#define glIsBuffer glad_glIsBuffer
+GLAD_API_CALL PFNGLISENABLEDPROC glad_glIsEnabled;
+#define glIsEnabled glad_glIsEnabled
+GLAD_API_CALL PFNGLISENABLEDIPROC glad_glIsEnabledi;
+#define glIsEnabledi glad_glIsEnabledi
+GLAD_API_CALL PFNGLISFRAMEBUFFERPROC glad_glIsFramebuffer;
+#define glIsFramebuffer glad_glIsFramebuffer
+GLAD_API_CALL PFNGLISPROGRAMPROC glad_glIsProgram;
+#define glIsProgram glad_glIsProgram
+GLAD_API_CALL PFNGLISQUERYPROC glad_glIsQuery;
+#define glIsQuery glad_glIsQuery
+GLAD_API_CALL PFNGLISRENDERBUFFERPROC glad_glIsRenderbuffer;
+#define glIsRenderbuffer glad_glIsRenderbuffer
+GLAD_API_CALL PFNGLISSAMPLERPROC glad_glIsSampler;
+#define glIsSampler glad_glIsSampler
+GLAD_API_CALL PFNGLISSHADERPROC glad_glIsShader;
+#define glIsShader glad_glIsShader
+GLAD_API_CALL PFNGLISSYNCPROC glad_glIsSync;
+#define glIsSync glad_glIsSync
+GLAD_API_CALL PFNGLISTEXTUREPROC glad_glIsTexture;
+#define glIsTexture glad_glIsTexture
+GLAD_API_CALL PFNGLISVERTEXARRAYPROC glad_glIsVertexArray;
+#define glIsVertexArray glad_glIsVertexArray
+GLAD_API_CALL PFNGLLINEWIDTHPROC glad_glLineWidth;
+#define glLineWidth glad_glLineWidth
+GLAD_API_CALL PFNGLLINKPROGRAMPROC glad_glLinkProgram;
+#define glLinkProgram glad_glLinkProgram
+GLAD_API_CALL PFNGLLOGICOPPROC glad_glLogicOp;
+#define glLogicOp glad_glLogicOp
+GLAD_API_CALL PFNGLMAPBUFFERPROC glad_glMapBuffer;
+#define glMapBuffer glad_glMapBuffer
+GLAD_API_CALL PFNGLMAPBUFFERRANGEPROC glad_glMapBufferRange;
+#define glMapBufferRange glad_glMapBufferRange
+GLAD_API_CALL PFNGLMULTIDRAWARRAYSPROC glad_glMultiDrawArrays;
+#define glMultiDrawArrays glad_glMultiDrawArrays
+GLAD_API_CALL PFNGLMULTIDRAWELEMENTSPROC glad_glMultiDrawElements;
+#define glMultiDrawElements glad_glMultiDrawElements
+GLAD_API_CALL PFNGLMULTIDRAWELEMENTSBASEVERTEXPROC glad_glMultiDrawElementsBaseVertex;
+#define glMultiDrawElementsBaseVertex glad_glMultiDrawElementsBaseVertex
+GLAD_API_CALL PFNGLPIXELSTOREFPROC glad_glPixelStoref;
+#define glPixelStoref glad_glPixelStoref
+GLAD_API_CALL PFNGLPIXELSTOREIPROC glad_glPixelStorei;
+#define glPixelStorei glad_glPixelStorei
+GLAD_API_CALL PFNGLPOINTPARAMETERFPROC glad_glPointParameterf;
+#define glPointParameterf glad_glPointParameterf
+GLAD_API_CALL PFNGLPOINTPARAMETERFVPROC glad_glPointParameterfv;
+#define glPointParameterfv glad_glPointParameterfv
+GLAD_API_CALL PFNGLPOINTPARAMETERIPROC glad_glPointParameteri;
+#define glPointParameteri glad_glPointParameteri
+GLAD_API_CALL PFNGLPOINTPARAMETERIVPROC glad_glPointParameteriv;
+#define glPointParameteriv glad_glPointParameteriv
+GLAD_API_CALL PFNGLPOINTSIZEPROC glad_glPointSize;
+#define glPointSize glad_glPointSize
+GLAD_API_CALL PFNGLPOLYGONMODEPROC glad_glPolygonMode;
+#define glPolygonMode glad_glPolygonMode
+GLAD_API_CALL PFNGLPOLYGONOFFSETPROC glad_glPolygonOffset;
+#define glPolygonOffset glad_glPolygonOffset
+GLAD_API_CALL PFNGLPRIMITIVERESTARTINDEXPROC glad_glPrimitiveRestartIndex;
+#define glPrimitiveRestartIndex glad_glPrimitiveRestartIndex
+GLAD_API_CALL PFNGLPROVOKINGVERTEXPROC glad_glProvokingVertex;
+#define glProvokingVertex glad_glProvokingVertex
+GLAD_API_CALL PFNGLQUERYCOUNTERPROC glad_glQueryCounter;
+#define glQueryCounter glad_glQueryCounter
+GLAD_API_CALL PFNGLREADBUFFERPROC glad_glReadBuffer;
+#define glReadBuffer glad_glReadBuffer
+GLAD_API_CALL PFNGLREADPIXELSPROC glad_glReadPixels;
+#define glReadPixels glad_glReadPixels
+GLAD_API_CALL PFNGLRENDERBUFFERSTORAGEPROC glad_glRenderbufferStorage;
+#define glRenderbufferStorage glad_glRenderbufferStorage
+GLAD_API_CALL PFNGLRENDERBUFFERSTORAGEMULTISAMPLEPROC glad_glRenderbufferStorageMultisample;
+#define glRenderbufferStorageMultisample glad_glRenderbufferStorageMultisample
+GLAD_API_CALL PFNGLSAMPLECOVERAGEPROC glad_glSampleCoverage;
+#define glSampleCoverage glad_glSampleCoverage
+GLAD_API_CALL PFNGLSAMPLEMASKIPROC glad_glSampleMaski;
+#define glSampleMaski glad_glSampleMaski
+GLAD_API_CALL PFNGLSAMPLERPARAMETERIIVPROC glad_glSamplerParameterIiv;
+#define glSamplerParameterIiv glad_glSamplerParameterIiv
+GLAD_API_CALL PFNGLSAMPLERPARAMETERIUIVPROC glad_glSamplerParameterIuiv;
+#define glSamplerParameterIuiv glad_glSamplerParameterIuiv
+GLAD_API_CALL PFNGLSAMPLERPARAMETERFPROC glad_glSamplerParameterf;
+#define glSamplerParameterf glad_glSamplerParameterf
+GLAD_API_CALL PFNGLSAMPLERPARAMETERFVPROC glad_glSamplerParameterfv;
+#define glSamplerParameterfv glad_glSamplerParameterfv
+GLAD_API_CALL PFNGLSAMPLERPARAMETERIPROC glad_glSamplerParameteri;
+#define glSamplerParameteri glad_glSamplerParameteri
+GLAD_API_CALL PFNGLSAMPLERPARAMETERIVPROC glad_glSamplerParameteriv;
+#define glSamplerParameteriv glad_glSamplerParameteriv
+GLAD_API_CALL PFNGLSCISSORPROC glad_glScissor;
+#define glScissor glad_glScissor
+GLAD_API_CALL PFNGLSHADERSOURCEPROC glad_glShaderSource;
+#define glShaderSource glad_glShaderSource
+GLAD_API_CALL PFNGLSTENCILFUNCPROC glad_glStencilFunc;
+#define glStencilFunc glad_glStencilFunc
+GLAD_API_CALL PFNGLSTENCILFUNCSEPARATEPROC glad_glStencilFuncSeparate;
+#define glStencilFuncSeparate glad_glStencilFuncSeparate
+GLAD_API_CALL PFNGLSTENCILMASKPROC glad_glStencilMask;
+#define glStencilMask glad_glStencilMask
+GLAD_API_CALL PFNGLSTENCILMASKSEPARATEPROC glad_glStencilMaskSeparate;
+#define glStencilMaskSeparate glad_glStencilMaskSeparate
+GLAD_API_CALL PFNGLSTENCILOPPROC glad_glStencilOp;
+#define glStencilOp glad_glStencilOp
+GLAD_API_CALL PFNGLSTENCILOPSEPARATEPROC glad_glStencilOpSeparate;
+#define glStencilOpSeparate glad_glStencilOpSeparate
+GLAD_API_CALL PFNGLTEXBUFFERPROC glad_glTexBuffer;
+#define glTexBuffer glad_glTexBuffer
+GLAD_API_CALL PFNGLTEXIMAGE1DPROC glad_glTexImage1D;
+#define glTexImage1D glad_glTexImage1D
+GLAD_API_CALL PFNGLTEXIMAGE2DPROC glad_glTexImage2D;
+#define glTexImage2D glad_glTexImage2D
+GLAD_API_CALL PFNGLTEXIMAGE2DMULTISAMPLEPROC glad_glTexImage2DMultisample;
+#define glTexImage2DMultisample glad_glTexImage2DMultisample
+GLAD_API_CALL PFNGLTEXIMAGE3DPROC glad_glTexImage3D;
+#define glTexImage3D glad_glTexImage3D
+GLAD_API_CALL PFNGLTEXIMAGE3DMULTISAMPLEPROC glad_glTexImage3DMultisample;
+#define glTexImage3DMultisample glad_glTexImage3DMultisample
+GLAD_API_CALL PFNGLTEXPARAMETERIIVPROC glad_glTexParameterIiv;
+#define glTexParameterIiv glad_glTexParameterIiv
+GLAD_API_CALL PFNGLTEXPARAMETERIUIVPROC glad_glTexParameterIuiv;
+#define glTexParameterIuiv glad_glTexParameterIuiv
+GLAD_API_CALL PFNGLTEXPARAMETERFPROC glad_glTexParameterf;
+#define glTexParameterf glad_glTexParameterf
+GLAD_API_CALL PFNGLTEXPARAMETERFVPROC glad_glTexParameterfv;
+#define glTexParameterfv glad_glTexParameterfv
+GLAD_API_CALL PFNGLTEXPARAMETERIPROC glad_glTexParameteri;
+#define glTexParameteri glad_glTexParameteri
+GLAD_API_CALL PFNGLTEXPARAMETERIVPROC glad_glTexParameteriv;
+#define glTexParameteriv glad_glTexParameteriv
+GLAD_API_CALL PFNGLTEXSUBIMAGE1DPROC glad_glTexSubImage1D;
+#define glTexSubImage1D glad_glTexSubImage1D
+GLAD_API_CALL PFNGLTEXSUBIMAGE2DPROC glad_glTexSubImage2D;
+#define glTexSubImage2D glad_glTexSubImage2D
+GLAD_API_CALL PFNGLTEXSUBIMAGE3DPROC glad_glTexSubImage3D;
+#define glTexSubImage3D glad_glTexSubImage3D
+GLAD_API_CALL PFNGLTRANSFORMFEEDBACKVARYINGSPROC glad_glTransformFeedbackVaryings;
+#define glTransformFeedbackVaryings glad_glTransformFeedbackVaryings
+GLAD_API_CALL PFNGLUNIFORM1FPROC glad_glUniform1f;
+#define glUniform1f glad_glUniform1f
+GLAD_API_CALL PFNGLUNIFORM1FVPROC glad_glUniform1fv;
+#define glUniform1fv glad_glUniform1fv
+GLAD_API_CALL PFNGLUNIFORM1IPROC glad_glUniform1i;
+#define glUniform1i glad_glUniform1i
+GLAD_API_CALL PFNGLUNIFORM1IVPROC glad_glUniform1iv;
+#define glUniform1iv glad_glUniform1iv
+GLAD_API_CALL PFNGLUNIFORM1UIPROC glad_glUniform1ui;
+#define glUniform1ui glad_glUniform1ui
+GLAD_API_CALL PFNGLUNIFORM1UIVPROC glad_glUniform1uiv;
+#define glUniform1uiv glad_glUniform1uiv
+GLAD_API_CALL PFNGLUNIFORM2FPROC glad_glUniform2f;
+#define glUniform2f glad_glUniform2f
+GLAD_API_CALL PFNGLUNIFORM2FVPROC glad_glUniform2fv;
+#define glUniform2fv glad_glUniform2fv
+GLAD_API_CALL PFNGLUNIFORM2IPROC glad_glUniform2i;
+#define glUniform2i glad_glUniform2i
+GLAD_API_CALL PFNGLUNIFORM2IVPROC glad_glUniform2iv;
+#define glUniform2iv glad_glUniform2iv
+GLAD_API_CALL PFNGLUNIFORM2UIPROC glad_glUniform2ui;
+#define glUniform2ui glad_glUniform2ui
+GLAD_API_CALL PFNGLUNIFORM2UIVPROC glad_glUniform2uiv;
+#define glUniform2uiv glad_glUniform2uiv
+GLAD_API_CALL PFNGLUNIFORM3FPROC glad_glUniform3f;
+#define glUniform3f glad_glUniform3f
+GLAD_API_CALL PFNGLUNIFORM3FVPROC glad_glUniform3fv;
+#define glUniform3fv glad_glUniform3fv
+GLAD_API_CALL PFNGLUNIFORM3IPROC glad_glUniform3i;
+#define glUniform3i glad_glUniform3i
+GLAD_API_CALL PFNGLUNIFORM3IVPROC glad_glUniform3iv;
+#define glUniform3iv glad_glUniform3iv
+GLAD_API_CALL PFNGLUNIFORM3UIPROC glad_glUniform3ui;
+#define glUniform3ui glad_glUniform3ui
+GLAD_API_CALL PFNGLUNIFORM3UIVPROC glad_glUniform3uiv;
+#define glUniform3uiv glad_glUniform3uiv
+GLAD_API_CALL PFNGLUNIFORM4FPROC glad_glUniform4f;
+#define glUniform4f glad_glUniform4f
+GLAD_API_CALL PFNGLUNIFORM4FVPROC glad_glUniform4fv;
+#define glUniform4fv glad_glUniform4fv
+GLAD_API_CALL PFNGLUNIFORM4IPROC glad_glUniform4i;
+#define glUniform4i glad_glUniform4i
+GLAD_API_CALL PFNGLUNIFORM4IVPROC glad_glUniform4iv;
+#define glUniform4iv glad_glUniform4iv
+GLAD_API_CALL PFNGLUNIFORM4UIPROC glad_glUniform4ui;
+#define glUniform4ui glad_glUniform4ui
+GLAD_API_CALL PFNGLUNIFORM4UIVPROC glad_glUniform4uiv;
+#define glUniform4uiv glad_glUniform4uiv
+GLAD_API_CALL PFNGLUNIFORMBLOCKBINDINGPROC glad_glUniformBlockBinding;
+#define glUniformBlockBinding glad_glUniformBlockBinding
+GLAD_API_CALL PFNGLUNIFORMMATRIX2FVPROC glad_glUniformMatrix2fv;
+#define glUniformMatrix2fv glad_glUniformMatrix2fv
+GLAD_API_CALL PFNGLUNIFORMMATRIX2X3FVPROC glad_glUniformMatrix2x3fv;
+#define glUniformMatrix2x3fv glad_glUniformMatrix2x3fv
+GLAD_API_CALL PFNGLUNIFORMMATRIX2X4FVPROC glad_glUniformMatrix2x4fv;
+#define glUniformMatrix2x4fv glad_glUniformMatrix2x4fv
+GLAD_API_CALL PFNGLUNIFORMMATRIX3FVPROC glad_glUniformMatrix3fv;
+#define glUniformMatrix3fv glad_glUniformMatrix3fv
+GLAD_API_CALL PFNGLUNIFORMMATRIX3X2FVPROC glad_glUniformMatrix3x2fv;
+#define glUniformMatrix3x2fv glad_glUniformMatrix3x2fv
+GLAD_API_CALL PFNGLUNIFORMMATRIX3X4FVPROC glad_glUniformMatrix3x4fv;
+#define glUniformMatrix3x4fv glad_glUniformMatrix3x4fv
+GLAD_API_CALL PFNGLUNIFORMMATRIX4FVPROC glad_glUniformMatrix4fv;
+#define glUniformMatrix4fv glad_glUniformMatrix4fv
+GLAD_API_CALL PFNGLUNIFORMMATRIX4X2FVPROC glad_glUniformMatrix4x2fv;
+#define glUniformMatrix4x2fv glad_glUniformMatrix4x2fv
+GLAD_API_CALL PFNGLUNIFORMMATRIX4X3FVPROC glad_glUniformMatrix4x3fv;
+#define glUniformMatrix4x3fv glad_glUniformMatrix4x3fv
+GLAD_API_CALL PFNGLUNMAPBUFFERPROC glad_glUnmapBuffer;
+#define glUnmapBuffer glad_glUnmapBuffer
+GLAD_API_CALL PFNGLUSEPROGRAMPROC glad_glUseProgram;
+#define glUseProgram glad_glUseProgram
+GLAD_API_CALL PFNGLVALIDATEPROGRAMPROC glad_glValidateProgram;
+#define glValidateProgram glad_glValidateProgram
+GLAD_API_CALL PFNGLVERTEXATTRIB1DPROC glad_glVertexAttrib1d;
+#define glVertexAttrib1d glad_glVertexAttrib1d
+GLAD_API_CALL PFNGLVERTEXATTRIB1DVPROC glad_glVertexAttrib1dv;
+#define glVertexAttrib1dv glad_glVertexAttrib1dv
+GLAD_API_CALL PFNGLVERTEXATTRIB1FPROC glad_glVertexAttrib1f;
+#define glVertexAttrib1f glad_glVertexAttrib1f
+GLAD_API_CALL PFNGLVERTEXATTRIB1FVPROC glad_glVertexAttrib1fv;
+#define glVertexAttrib1fv glad_glVertexAttrib1fv
+GLAD_API_CALL PFNGLVERTEXATTRIB1SPROC glad_glVertexAttrib1s;
+#define glVertexAttrib1s glad_glVertexAttrib1s
+GLAD_API_CALL PFNGLVERTEXATTRIB1SVPROC glad_glVertexAttrib1sv;
+#define glVertexAttrib1sv glad_glVertexAttrib1sv
+GLAD_API_CALL PFNGLVERTEXATTRIB2DPROC glad_glVertexAttrib2d;
+#define glVertexAttrib2d glad_glVertexAttrib2d
+GLAD_API_CALL PFNGLVERTEXATTRIB2DVPROC glad_glVertexAttrib2dv;
+#define glVertexAttrib2dv glad_glVertexAttrib2dv
+GLAD_API_CALL PFNGLVERTEXATTRIB2FPROC glad_glVertexAttrib2f;
+#define glVertexAttrib2f glad_glVertexAttrib2f
+GLAD_API_CALL PFNGLVERTEXATTRIB2FVPROC glad_glVertexAttrib2fv;
+#define glVertexAttrib2fv glad_glVertexAttrib2fv
+GLAD_API_CALL PFNGLVERTEXATTRIB2SPROC glad_glVertexAttrib2s;
+#define glVertexAttrib2s glad_glVertexAttrib2s
+GLAD_API_CALL PFNGLVERTEXATTRIB2SVPROC glad_glVertexAttrib2sv;
+#define glVertexAttrib2sv glad_glVertexAttrib2sv
+GLAD_API_CALL PFNGLVERTEXATTRIB3DPROC glad_glVertexAttrib3d;
+#define glVertexAttrib3d glad_glVertexAttrib3d
+GLAD_API_CALL PFNGLVERTEXATTRIB3DVPROC glad_glVertexAttrib3dv;
+#define glVertexAttrib3dv glad_glVertexAttrib3dv
+GLAD_API_CALL PFNGLVERTEXATTRIB3FPROC glad_glVertexAttrib3f;
+#define glVertexAttrib3f glad_glVertexAttrib3f
+GLAD_API_CALL PFNGLVERTEXATTRIB3FVPROC glad_glVertexAttrib3fv;
+#define glVertexAttrib3fv glad_glVertexAttrib3fv
+GLAD_API_CALL PFNGLVERTEXATTRIB3SPROC glad_glVertexAttrib3s;
+#define glVertexAttrib3s glad_glVertexAttrib3s
+GLAD_API_CALL PFNGLVERTEXATTRIB3SVPROC glad_glVertexAttrib3sv;
+#define glVertexAttrib3sv glad_glVertexAttrib3sv
+GLAD_API_CALL PFNGLVERTEXATTRIB4NBVPROC glad_glVertexAttrib4Nbv;
+#define glVertexAttrib4Nbv glad_glVertexAttrib4Nbv
+GLAD_API_CALL PFNGLVERTEXATTRIB4NIVPROC glad_glVertexAttrib4Niv;
+#define glVertexAttrib4Niv glad_glVertexAttrib4Niv
+GLAD_API_CALL PFNGLVERTEXATTRIB4NSVPROC glad_glVertexAttrib4Nsv;
+#define glVertexAttrib4Nsv glad_glVertexAttrib4Nsv
+GLAD_API_CALL PFNGLVERTEXATTRIB4NUBPROC glad_glVertexAttrib4Nub;
+#define glVertexAttrib4Nub glad_glVertexAttrib4Nub
+GLAD_API_CALL PFNGLVERTEXATTRIB4NUBVPROC glad_glVertexAttrib4Nubv;
+#define glVertexAttrib4Nubv glad_glVertexAttrib4Nubv
+GLAD_API_CALL PFNGLVERTEXATTRIB4NUIVPROC glad_glVertexAttrib4Nuiv;
+#define glVertexAttrib4Nuiv glad_glVertexAttrib4Nuiv
+GLAD_API_CALL PFNGLVERTEXATTRIB4NUSVPROC glad_glVertexAttrib4Nusv;
+#define glVertexAttrib4Nusv glad_glVertexAttrib4Nusv
+GLAD_API_CALL PFNGLVERTEXATTRIB4BVPROC glad_glVertexAttrib4bv;
+#define glVertexAttrib4bv glad_glVertexAttrib4bv
+GLAD_API_CALL PFNGLVERTEXATTRIB4DPROC glad_glVertexAttrib4d;
+#define glVertexAttrib4d glad_glVertexAttrib4d
+GLAD_API_CALL PFNGLVERTEXATTRIB4DVPROC glad_glVertexAttrib4dv;
+#define glVertexAttrib4dv glad_glVertexAttrib4dv
+GLAD_API_CALL PFNGLVERTEXATTRIB4FPROC glad_glVertexAttrib4f;
+#define glVertexAttrib4f glad_glVertexAttrib4f
+GLAD_API_CALL PFNGLVERTEXATTRIB4FVPROC glad_glVertexAttrib4fv;
+#define glVertexAttrib4fv glad_glVertexAttrib4fv
+GLAD_API_CALL PFNGLVERTEXATTRIB4IVPROC glad_glVertexAttrib4iv;
+#define glVertexAttrib4iv glad_glVertexAttrib4iv
+GLAD_API_CALL PFNGLVERTEXATTRIB4SPROC glad_glVertexAttrib4s;
+#define glVertexAttrib4s glad_glVertexAttrib4s
+GLAD_API_CALL PFNGLVERTEXATTRIB4SVPROC glad_glVertexAttrib4sv;
+#define glVertexAttrib4sv glad_glVertexAttrib4sv
+GLAD_API_CALL PFNGLVERTEXATTRIB4UBVPROC glad_glVertexAttrib4ubv;
+#define glVertexAttrib4ubv glad_glVertexAttrib4ubv
+GLAD_API_CALL PFNGLVERTEXATTRIB4UIVPROC glad_glVertexAttrib4uiv;
+#define glVertexAttrib4uiv glad_glVertexAttrib4uiv
+GLAD_API_CALL PFNGLVERTEXATTRIB4USVPROC glad_glVertexAttrib4usv;
+#define glVertexAttrib4usv glad_glVertexAttrib4usv
+GLAD_API_CALL PFNGLVERTEXATTRIBDIVISORPROC glad_glVertexAttribDivisor;
+#define glVertexAttribDivisor glad_glVertexAttribDivisor
+GLAD_API_CALL PFNGLVERTEXATTRIBI1IPROC glad_glVertexAttribI1i;
+#define glVertexAttribI1i glad_glVertexAttribI1i
+GLAD_API_CALL PFNGLVERTEXATTRIBI1IVPROC glad_glVertexAttribI1iv;
+#define glVertexAttribI1iv glad_glVertexAttribI1iv
+GLAD_API_CALL PFNGLVERTEXATTRIBI1UIPROC glad_glVertexAttribI1ui;
+#define glVertexAttribI1ui glad_glVertexAttribI1ui
+GLAD_API_CALL PFNGLVERTEXATTRIBI1UIVPROC glad_glVertexAttribI1uiv;
+#define glVertexAttribI1uiv glad_glVertexAttribI1uiv
+GLAD_API_CALL PFNGLVERTEXATTRIBI2IPROC glad_glVertexAttribI2i;
+#define glVertexAttribI2i glad_glVertexAttribI2i
+GLAD_API_CALL PFNGLVERTEXATTRIBI2IVPROC glad_glVertexAttribI2iv;
+#define glVertexAttribI2iv glad_glVertexAttribI2iv
+GLAD_API_CALL PFNGLVERTEXATTRIBI2UIPROC glad_glVertexAttribI2ui;
+#define glVertexAttribI2ui glad_glVertexAttribI2ui
+GLAD_API_CALL PFNGLVERTEXATTRIBI2UIVPROC glad_glVertexAttribI2uiv;
+#define glVertexAttribI2uiv glad_glVertexAttribI2uiv
+GLAD_API_CALL PFNGLVERTEXATTRIBI3IPROC glad_glVertexAttribI3i;
+#define glVertexAttribI3i glad_glVertexAttribI3i
+GLAD_API_CALL PFNGLVERTEXATTRIBI3IVPROC glad_glVertexAttribI3iv;
+#define glVertexAttribI3iv glad_glVertexAttribI3iv
+GLAD_API_CALL PFNGLVERTEXATTRIBI3UIPROC glad_glVertexAttribI3ui;
+#define glVertexAttribI3ui glad_glVertexAttribI3ui
+GLAD_API_CALL PFNGLVERTEXATTRIBI3UIVPROC glad_glVertexAttribI3uiv;
+#define glVertexAttribI3uiv glad_glVertexAttribI3uiv
+GLAD_API_CALL PFNGLVERTEXATTRIBI4BVPROC glad_glVertexAttribI4bv;
+#define glVertexAttribI4bv glad_glVertexAttribI4bv
+GLAD_API_CALL PFNGLVERTEXATTRIBI4IPROC glad_glVertexAttribI4i;
+#define glVertexAttribI4i glad_glVertexAttribI4i
+GLAD_API_CALL PFNGLVERTEXATTRIBI4IVPROC glad_glVertexAttribI4iv;
+#define glVertexAttribI4iv glad_glVertexAttribI4iv
+GLAD_API_CALL PFNGLVERTEXATTRIBI4SVPROC glad_glVertexAttribI4sv;
+#define glVertexAttribI4sv glad_glVertexAttribI4sv
+GLAD_API_CALL PFNGLVERTEXATTRIBI4UBVPROC glad_glVertexAttribI4ubv;
+#define glVertexAttribI4ubv glad_glVertexAttribI4ubv
+GLAD_API_CALL PFNGLVERTEXATTRIBI4UIPROC glad_glVertexAttribI4ui;
+#define glVertexAttribI4ui glad_glVertexAttribI4ui
+GLAD_API_CALL PFNGLVERTEXATTRIBI4UIVPROC glad_glVertexAttribI4uiv;
+#define glVertexAttribI4uiv glad_glVertexAttribI4uiv
+GLAD_API_CALL PFNGLVERTEXATTRIBI4USVPROC glad_glVertexAttribI4usv;
+#define glVertexAttribI4usv glad_glVertexAttribI4usv
+GLAD_API_CALL PFNGLVERTEXATTRIBIPOINTERPROC glad_glVertexAttribIPointer;
+#define glVertexAttribIPointer glad_glVertexAttribIPointer
+GLAD_API_CALL PFNGLVERTEXATTRIBP1UIPROC glad_glVertexAttribP1ui;
+#define glVertexAttribP1ui glad_glVertexAttribP1ui
+GLAD_API_CALL PFNGLVERTEXATTRIBP1UIVPROC glad_glVertexAttribP1uiv;
+#define glVertexAttribP1uiv glad_glVertexAttribP1uiv
+GLAD_API_CALL PFNGLVERTEXATTRIBP2UIPROC glad_glVertexAttribP2ui;
+#define glVertexAttribP2ui glad_glVertexAttribP2ui
+GLAD_API_CALL PFNGLVERTEXATTRIBP2UIVPROC glad_glVertexAttribP2uiv;
+#define glVertexAttribP2uiv glad_glVertexAttribP2uiv
+GLAD_API_CALL PFNGLVERTEXATTRIBP3UIPROC glad_glVertexAttribP3ui;
+#define glVertexAttribP3ui glad_glVertexAttribP3ui
+GLAD_API_CALL PFNGLVERTEXATTRIBP3UIVPROC glad_glVertexAttribP3uiv;
+#define glVertexAttribP3uiv glad_glVertexAttribP3uiv
+GLAD_API_CALL PFNGLVERTEXATTRIBP4UIPROC glad_glVertexAttribP4ui;
+#define glVertexAttribP4ui glad_glVertexAttribP4ui
+GLAD_API_CALL PFNGLVERTEXATTRIBP4UIVPROC glad_glVertexAttribP4uiv;
+#define glVertexAttribP4uiv glad_glVertexAttribP4uiv
+GLAD_API_CALL PFNGLVERTEXATTRIBPOINTERPROC glad_glVertexAttribPointer;
+#define glVertexAttribPointer glad_glVertexAttribPointer
+GLAD_API_CALL PFNGLVIEWPORTPROC glad_glViewport;
+#define glViewport glad_glViewport
+GLAD_API_CALL PFNGLWAITSYNCPROC glad_glWaitSync;
+#define glWaitSync glad_glWaitSync
+
+
+
+
+
+GLAD_API_CALL int gladLoadGLUserPtr( GLADuserptrloadfunc load, void *userptr);
+GLAD_API_CALL int gladLoadGL( GLADloadfunc load);
+
+
+#ifdef GLAD_GL
+
+GLAD_API_CALL int gladLoaderLoadGL(void);
+GLAD_API_CALL void gladLoaderUnloadGL(void);
+
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+#endif
+
+/* Source */
+#ifdef GLAD_GL_IMPLEMENTATION
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#ifndef GLAD_IMPL_UTIL_C_
+#define GLAD_IMPL_UTIL_C_
+
+#ifdef _MSC_VER
+#define GLAD_IMPL_UTIL_SSCANF sscanf_s
+#else
+#define GLAD_IMPL_UTIL_SSCANF sscanf
+#endif
+
+#endif /* GLAD_IMPL_UTIL_C_ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+
+int GLAD_GL_VERSION_1_0 = 0;
+int GLAD_GL_VERSION_1_1 = 0;
+int GLAD_GL_VERSION_1_2 = 0;
+int GLAD_GL_VERSION_1_3 = 0;
+int GLAD_GL_VERSION_1_4 = 0;
+int GLAD_GL_VERSION_1_5 = 0;
+int GLAD_GL_VERSION_2_0 = 0;
+int GLAD_GL_VERSION_2_1 = 0;
+int GLAD_GL_VERSION_3_0 = 0;
+int GLAD_GL_VERSION_3_1 = 0;
+int GLAD_GL_VERSION_3_2 = 0;
+int GLAD_GL_VERSION_3_3 = 0;
+
+
+
+PFNGLACTIVETEXTUREPROC glad_glActiveTexture = NULL;
+PFNGLATTACHSHADERPROC glad_glAttachShader = NULL;
+PFNGLBEGINCONDITIONALRENDERPROC glad_glBeginConditionalRender = NULL;
+PFNGLBEGINQUERYPROC glad_glBeginQuery = NULL;
+PFNGLBEGINTRANSFORMFEEDBACKPROC glad_glBeginTransformFeedback = NULL;
+PFNGLBINDATTRIBLOCATIONPROC glad_glBindAttribLocation = NULL;
+PFNGLBINDBUFFERPROC glad_glBindBuffer = NULL;
+PFNGLBINDBUFFERBASEPROC glad_glBindBufferBase = NULL;
+PFNGLBINDBUFFERRANGEPROC glad_glBindBufferRange = NULL;
+PFNGLBINDFRAGDATALOCATIONPROC glad_glBindFragDataLocation = NULL;
+PFNGLBINDFRAGDATALOCATIONINDEXEDPROC glad_glBindFragDataLocationIndexed = NULL;
+PFNGLBINDFRAMEBUFFERPROC glad_glBindFramebuffer = NULL;
+PFNGLBINDRENDERBUFFERPROC glad_glBindRenderbuffer = NULL;
+PFNGLBINDSAMPLERPROC glad_glBindSampler = NULL;
+PFNGLBINDTEXTUREPROC glad_glBindTexture = NULL;
+PFNGLBINDVERTEXARRAYPROC glad_glBindVertexArray = NULL;
+PFNGLBLENDCOLORPROC glad_glBlendColor = NULL;
+PFNGLBLENDEQUATIONPROC glad_glBlendEquation = NULL;
+PFNGLBLENDEQUATIONSEPARATEPROC glad_glBlendEquationSeparate = NULL;
+PFNGLBLENDFUNCPROC glad_glBlendFunc = NULL;
+PFNGLBLENDFUNCSEPARATEPROC glad_glBlendFuncSeparate = NULL;
+PFNGLBLITFRAMEBUFFERPROC glad_glBlitFramebuffer = NULL;
+PFNGLBUFFERDATAPROC glad_glBufferData = NULL;
+PFNGLBUFFERSUBDATAPROC glad_glBufferSubData = NULL;
+PFNGLCHECKFRAMEBUFFERSTATUSPROC glad_glCheckFramebufferStatus = NULL;
+PFNGLCLAMPCOLORPROC glad_glClampColor = NULL;
+PFNGLCLEARPROC glad_glClear = NULL;
+PFNGLCLEARBUFFERFIPROC glad_glClearBufferfi = NULL;
+PFNGLCLEARBUFFERFVPROC glad_glClearBufferfv = NULL;
+PFNGLCLEARBUFFERIVPROC glad_glClearBufferiv = NULL;
+PFNGLCLEARBUFFERUIVPROC glad_glClearBufferuiv = NULL;
+PFNGLCLEARCOLORPROC glad_glClearColor = NULL;
+PFNGLCLEARDEPTHPROC glad_glClearDepth = NULL;
+PFNGLCLEARSTENCILPROC glad_glClearStencil = NULL;
+PFNGLCLIENTWAITSYNCPROC glad_glClientWaitSync = NULL;
+PFNGLCOLORMASKPROC glad_glColorMask = NULL;
+PFNGLCOLORMASKIPROC glad_glColorMaski = NULL;
+PFNGLCOMPILESHADERPROC glad_glCompileShader = NULL;
+PFNGLCOMPRESSEDTEXIMAGE1DPROC glad_glCompressedTexImage1D = NULL;
+PFNGLCOMPRESSEDTEXIMAGE2DPROC glad_glCompressedTexImage2D = NULL;
+PFNGLCOMPRESSEDTEXIMAGE3DPROC glad_glCompressedTexImage3D = NULL;
+PFNGLCOMPRESSEDTEXSUBIMAGE1DPROC glad_glCompressedTexSubImage1D = NULL;
+PFNGLCOMPRESSEDTEXSUBIMAGE2DPROC glad_glCompressedTexSubImage2D = NULL;
+PFNGLCOMPRESSEDTEXSUBIMAGE3DPROC glad_glCompressedTexSubImage3D = NULL;
+PFNGLCOPYBUFFERSUBDATAPROC glad_glCopyBufferSubData = NULL;
+PFNGLCOPYTEXIMAGE1DPROC glad_glCopyTexImage1D = NULL;
+PFNGLCOPYTEXIMAGE2DPROC glad_glCopyTexImage2D = NULL;
+PFNGLCOPYTEXSUBIMAGE1DPROC glad_glCopyTexSubImage1D = NULL;
+PFNGLCOPYTEXSUBIMAGE2DPROC glad_glCopyTexSubImage2D = NULL;
+PFNGLCOPYTEXSUBIMAGE3DPROC glad_glCopyTexSubImage3D = NULL;
+PFNGLCREATEPROGRAMPROC glad_glCreateProgram = NULL;
+PFNGLCREATESHADERPROC glad_glCreateShader = NULL;
+PFNGLCULLFACEPROC glad_glCullFace = NULL;
+PFNGLDELETEBUFFERSPROC glad_glDeleteBuffers = NULL;
+PFNGLDELETEFRAMEBUFFERSPROC glad_glDeleteFramebuffers = NULL;
+PFNGLDELETEPROGRAMPROC glad_glDeleteProgram = NULL;
+PFNGLDELETEQUERIESPROC glad_glDeleteQueries = NULL;
+PFNGLDELETERENDERBUFFERSPROC glad_glDeleteRenderbuffers = NULL;
+PFNGLDELETESAMPLERSPROC glad_glDeleteSamplers = NULL;
+PFNGLDELETESHADERPROC glad_glDeleteShader = NULL;
+PFNGLDELETESYNCPROC glad_glDeleteSync = NULL;
+PFNGLDELETETEXTURESPROC glad_glDeleteTextures = NULL;
+PFNGLDELETEVERTEXARRAYSPROC glad_glDeleteVertexArrays = NULL;
+PFNGLDEPTHFUNCPROC glad_glDepthFunc = NULL;
+PFNGLDEPTHMASKPROC glad_glDepthMask = NULL;
+PFNGLDEPTHRANGEPROC glad_glDepthRange = NULL;
+PFNGLDETACHSHADERPROC glad_glDetachShader = NULL;
+PFNGLDISABLEPROC glad_glDisable = NULL;
+PFNGLDISABLEVERTEXATTRIBARRAYPROC glad_glDisableVertexAttribArray = NULL;
+PFNGLDISABLEIPROC glad_glDisablei = NULL;
+PFNGLDRAWARRAYSPROC glad_glDrawArrays = NULL;
+PFNGLDRAWARRAYSINSTANCEDPROC glad_glDrawArraysInstanced = NULL;
+PFNGLDRAWBUFFERPROC glad_glDrawBuffer = NULL;
+PFNGLDRAWBUFFERSPROC glad_glDrawBuffers = NULL;
+PFNGLDRAWELEMENTSPROC glad_glDrawElements = NULL;
+PFNGLDRAWELEMENTSBASEVERTEXPROC glad_glDrawElementsBaseVertex = NULL;
+PFNGLDRAWELEMENTSINSTANCEDPROC glad_glDrawElementsInstanced = NULL;
+PFNGLDRAWELEMENTSINSTANCEDBASEVERTEXPROC glad_glDrawElementsInstancedBaseVertex = NULL;
+PFNGLDRAWRANGEELEMENTSPROC glad_glDrawRangeElements = NULL;
+PFNGLDRAWRANGEELEMENTSBASEVERTEXPROC glad_glDrawRangeElementsBaseVertex = NULL;
+PFNGLENABLEPROC glad_glEnable = NULL;
+PFNGLENABLEVERTEXATTRIBARRAYPROC glad_glEnableVertexAttribArray = NULL;
+PFNGLENABLEIPROC glad_glEnablei = NULL;
+PFNGLENDCONDITIONALRENDERPROC glad_glEndConditionalRender = NULL;
+PFNGLENDQUERYPROC glad_glEndQuery = NULL;
+PFNGLENDTRANSFORMFEEDBACKPROC glad_glEndTransformFeedback = NULL;
+PFNGLFENCESYNCPROC glad_glFenceSync = NULL;
+PFNGLFINISHPROC glad_glFinish = NULL;
+PFNGLFLUSHPROC glad_glFlush = NULL;
+PFNGLFLUSHMAPPEDBUFFERRANGEPROC glad_glFlushMappedBufferRange = NULL;
+PFNGLFRAMEBUFFERRENDERBUFFERPROC glad_glFramebufferRenderbuffer = NULL;
+PFNGLFRAMEBUFFERTEXTUREPROC glad_glFramebufferTexture = NULL;
+PFNGLFRAMEBUFFERTEXTURE1DPROC glad_glFramebufferTexture1D = NULL;
+PFNGLFRAMEBUFFERTEXTURE2DPROC glad_glFramebufferTexture2D = NULL;
+PFNGLFRAMEBUFFERTEXTURE3DPROC glad_glFramebufferTexture3D = NULL;
+PFNGLFRAMEBUFFERTEXTURELAYERPROC glad_glFramebufferTextureLayer = NULL;
+PFNGLFRONTFACEPROC glad_glFrontFace = NULL;
+PFNGLGENBUFFERSPROC glad_glGenBuffers = NULL;
+PFNGLGENFRAMEBUFFERSPROC glad_glGenFramebuffers = NULL;
+PFNGLGENQUERIESPROC glad_glGenQueries = NULL;
+PFNGLGENRENDERBUFFERSPROC glad_glGenRenderbuffers = NULL;
+PFNGLGENSAMPLERSPROC glad_glGenSamplers = NULL;
+PFNGLGENTEXTURESPROC glad_glGenTextures = NULL;
+PFNGLGENVERTEXARRAYSPROC glad_glGenVertexArrays = NULL;
+PFNGLGENERATEMIPMAPPROC glad_glGenerateMipmap = NULL;
+PFNGLGETACTIVEATTRIBPROC glad_glGetActiveAttrib = NULL;
+PFNGLGETACTIVEUNIFORMPROC glad_glGetActiveUniform = NULL;
+PFNGLGETACTIVEUNIFORMBLOCKNAMEPROC glad_glGetActiveUniformBlockName = NULL;
+PFNGLGETACTIVEUNIFORMBLOCKIVPROC glad_glGetActiveUniformBlockiv = NULL;
+PFNGLGETACTIVEUNIFORMNAMEPROC glad_glGetActiveUniformName = NULL;
+PFNGLGETACTIVEUNIFORMSIVPROC glad_glGetActiveUniformsiv = NULL;
+PFNGLGETATTACHEDSHADERSPROC glad_glGetAttachedShaders = NULL;
+PFNGLGETATTRIBLOCATIONPROC glad_glGetAttribLocation = NULL;
+PFNGLGETBOOLEANI_VPROC glad_glGetBooleani_v = NULL;
+PFNGLGETBOOLEANVPROC glad_glGetBooleanv = NULL;
+PFNGLGETBUFFERPARAMETERI64VPROC glad_glGetBufferParameteri64v = NULL;
+PFNGLGETBUFFERPARAMETERIVPROC glad_glGetBufferParameteriv = NULL;
+PFNGLGETBUFFERPOINTERVPROC glad_glGetBufferPointerv = NULL;
+PFNGLGETBUFFERSUBDATAPROC glad_glGetBufferSubData = NULL;
+PFNGLGETCOMPRESSEDTEXIMAGEPROC glad_glGetCompressedTexImage = NULL;
+PFNGLGETDOUBLEVPROC glad_glGetDoublev = NULL;
+PFNGLGETERRORPROC glad_glGetError = NULL;
+PFNGLGETFLOATVPROC glad_glGetFloatv = NULL;
+PFNGLGETFRAGDATAINDEXPROC glad_glGetFragDataIndex = NULL;
+PFNGLGETFRAGDATALOCATIONPROC glad_glGetFragDataLocation = NULL;
+PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVPROC glad_glGetFramebufferAttachmentParameteriv = NULL;
+PFNGLGETINTEGER64I_VPROC glad_glGetInteger64i_v = NULL;
+PFNGLGETINTEGER64VPROC glad_glGetInteger64v = NULL;
+PFNGLGETINTEGERI_VPROC glad_glGetIntegeri_v = NULL;
+PFNGLGETINTEGERVPROC glad_glGetIntegerv = NULL;
+PFNGLGETMULTISAMPLEFVPROC glad_glGetMultisamplefv = NULL;
+PFNGLGETPROGRAMINFOLOGPROC glad_glGetProgramInfoLog = NULL;
+PFNGLGETPROGRAMIVPROC glad_glGetProgramiv = NULL;
+PFNGLGETQUERYOBJECTI64VPROC glad_glGetQueryObjecti64v = NULL;
+PFNGLGETQUERYOBJECTIVPROC glad_glGetQueryObjectiv = NULL;
+PFNGLGETQUERYOBJECTUI64VPROC glad_glGetQueryObjectui64v = NULL;
+PFNGLGETQUERYOBJECTUIVPROC glad_glGetQueryObjectuiv = NULL;
+PFNGLGETQUERYIVPROC glad_glGetQueryiv = NULL;
+PFNGLGETRENDERBUFFERPARAMETERIVPROC glad_glGetRenderbufferParameteriv = NULL;
+PFNGLGETSAMPLERPARAMETERIIVPROC glad_glGetSamplerParameterIiv = NULL;
+PFNGLGETSAMPLERPARAMETERIUIVPROC glad_glGetSamplerParameterIuiv = NULL;
+PFNGLGETSAMPLERPARAMETERFVPROC glad_glGetSamplerParameterfv = NULL;
+PFNGLGETSAMPLERPARAMETERIVPROC glad_glGetSamplerParameteriv = NULL;
+PFNGLGETSHADERINFOLOGPROC glad_glGetShaderInfoLog = NULL;
+PFNGLGETSHADERSOURCEPROC glad_glGetShaderSource = NULL;
+PFNGLGETSHADERIVPROC glad_glGetShaderiv = NULL;
+PFNGLGETSTRINGPROC glad_glGetString = NULL;
+PFNGLGETSTRINGIPROC glad_glGetStringi = NULL;
+PFNGLGETSYNCIVPROC glad_glGetSynciv = NULL;
+PFNGLGETTEXIMAGEPROC glad_glGetTexImage = NULL;
+PFNGLGETTEXLEVELPARAMETERFVPROC glad_glGetTexLevelParameterfv = NULL;
+PFNGLGETTEXLEVELPARAMETERIVPROC glad_glGetTexLevelParameteriv = NULL;
+PFNGLGETTEXPARAMETERIIVPROC glad_glGetTexParameterIiv = NULL;
+PFNGLGETTEXPARAMETERIUIVPROC glad_glGetTexParameterIuiv = NULL;
+PFNGLGETTEXPARAMETERFVPROC glad_glGetTexParameterfv = NULL;
+PFNGLGETTEXPARAMETERIVPROC glad_glGetTexParameteriv = NULL;
+PFNGLGETTRANSFORMFEEDBACKVARYINGPROC glad_glGetTransformFeedbackVarying = NULL;
+PFNGLGETUNIFORMBLOCKINDEXPROC glad_glGetUniformBlockIndex = NULL;
+PFNGLGETUNIFORMINDICESPROC glad_glGetUniformIndices = NULL;
+PFNGLGETUNIFORMLOCATIONPROC glad_glGetUniformLocation = NULL;
+PFNGLGETUNIFORMFVPROC glad_glGetUniformfv = NULL;
+PFNGLGETUNIFORMIVPROC glad_glGetUniformiv = NULL;
+PFNGLGETUNIFORMUIVPROC glad_glGetUniformuiv = NULL;
+PFNGLGETVERTEXATTRIBIIVPROC glad_glGetVertexAttribIiv = NULL;
+PFNGLGETVERTEXATTRIBIUIVPROC glad_glGetVertexAttribIuiv = NULL;
+PFNGLGETVERTEXATTRIBPOINTERVPROC glad_glGetVertexAttribPointerv = NULL;
+PFNGLGETVERTEXATTRIBDVPROC glad_glGetVertexAttribdv = NULL;
+PFNGLGETVERTEXATTRIBFVPROC glad_glGetVertexAttribfv = NULL;
+PFNGLGETVERTEXATTRIBIVPROC glad_glGetVertexAttribiv = NULL;
+PFNGLHINTPROC glad_glHint = NULL;
+PFNGLISBUFFERPROC glad_glIsBuffer = NULL;
+PFNGLISENABLEDPROC glad_glIsEnabled = NULL;
+PFNGLISENABLEDIPROC glad_glIsEnabledi = NULL;
+PFNGLISFRAMEBUFFERPROC glad_glIsFramebuffer = NULL;
+PFNGLISPROGRAMPROC glad_glIsProgram = NULL;
+PFNGLISQUERYPROC glad_glIsQuery = NULL;
+PFNGLISRENDERBUFFERPROC glad_glIsRenderbuffer = NULL;
+PFNGLISSAMPLERPROC glad_glIsSampler = NULL;
+PFNGLISSHADERPROC glad_glIsShader = NULL;
+PFNGLISSYNCPROC glad_glIsSync = NULL;
+PFNGLISTEXTUREPROC glad_glIsTexture = NULL;
+PFNGLISVERTEXARRAYPROC glad_glIsVertexArray = NULL;
+PFNGLLINEWIDTHPROC glad_glLineWidth = NULL;
+PFNGLLINKPROGRAMPROC glad_glLinkProgram = NULL;
+PFNGLLOGICOPPROC glad_glLogicOp = NULL;
+PFNGLMAPBUFFERPROC glad_glMapBuffer = NULL;
+PFNGLMAPBUFFERRANGEPROC glad_glMapBufferRange = NULL;
+PFNGLMULTIDRAWARRAYSPROC glad_glMultiDrawArrays = NULL;
+PFNGLMULTIDRAWELEMENTSPROC glad_glMultiDrawElements = NULL;
+PFNGLMULTIDRAWELEMENTSBASEVERTEXPROC glad_glMultiDrawElementsBaseVertex = NULL;
+PFNGLPIXELSTOREFPROC glad_glPixelStoref = NULL;
+PFNGLPIXELSTOREIPROC glad_glPixelStorei = NULL;
+PFNGLPOINTPARAMETERFPROC glad_glPointParameterf = NULL;
+PFNGLPOINTPARAMETERFVPROC glad_glPointParameterfv = NULL;
+PFNGLPOINTPARAMETERIPROC glad_glPointParameteri = NULL;
+PFNGLPOINTPARAMETERIVPROC glad_glPointParameteriv = NULL;
+PFNGLPOINTSIZEPROC glad_glPointSize = NULL;
+PFNGLPOLYGONMODEPROC glad_glPolygonMode = NULL;
+PFNGLPOLYGONOFFSETPROC glad_glPolygonOffset = NULL;
+PFNGLPRIMITIVERESTARTINDEXPROC glad_glPrimitiveRestartIndex = NULL;
+PFNGLPROVOKINGVERTEXPROC glad_glProvokingVertex = NULL;
+PFNGLQUERYCOUNTERPROC glad_glQueryCounter = NULL;
+PFNGLREADBUFFERPROC glad_glReadBuffer = NULL;
+PFNGLREADPIXELSPROC glad_glReadPixels = NULL;
+PFNGLRENDERBUFFERSTORAGEPROC glad_glRenderbufferStorage = NULL;
+PFNGLRENDERBUFFERSTORAGEMULTISAMPLEPROC glad_glRenderbufferStorageMultisample = NULL;
+PFNGLSAMPLECOVERAGEPROC glad_glSampleCoverage = NULL;
+PFNGLSAMPLEMASKIPROC glad_glSampleMaski = NULL;
+PFNGLSAMPLERPARAMETERIIVPROC glad_glSamplerParameterIiv = NULL;
+PFNGLSAMPLERPARAMETERIUIVPROC glad_glSamplerParameterIuiv = NULL;
+PFNGLSAMPLERPARAMETERFPROC glad_glSamplerParameterf = NULL;
+PFNGLSAMPLERPARAMETERFVPROC glad_glSamplerParameterfv = NULL;
+PFNGLSAMPLERPARAMETERIPROC glad_glSamplerParameteri = NULL;
+PFNGLSAMPLERPARAMETERIVPROC glad_glSamplerParameteriv = NULL;
+PFNGLSCISSORPROC glad_glScissor = NULL;
+PFNGLSHADERSOURCEPROC glad_glShaderSource = NULL;
+PFNGLSTENCILFUNCPROC glad_glStencilFunc = NULL;
+PFNGLSTENCILFUNCSEPARATEPROC glad_glStencilFuncSeparate = NULL;
+PFNGLSTENCILMASKPROC glad_glStencilMask = NULL;
+PFNGLSTENCILMASKSEPARATEPROC glad_glStencilMaskSeparate = NULL;
+PFNGLSTENCILOPPROC glad_glStencilOp = NULL;
+PFNGLSTENCILOPSEPARATEPROC glad_glStencilOpSeparate = NULL;
+PFNGLTEXBUFFERPROC glad_glTexBuffer = NULL;
+PFNGLTEXIMAGE1DPROC glad_glTexImage1D = NULL;
+PFNGLTEXIMAGE2DPROC glad_glTexImage2D = NULL;
+PFNGLTEXIMAGE2DMULTISAMPLEPROC glad_glTexImage2DMultisample = NULL;
+PFNGLTEXIMAGE3DPROC glad_glTexImage3D = NULL;
+PFNGLTEXIMAGE3DMULTISAMPLEPROC glad_glTexImage3DMultisample = NULL;
+PFNGLTEXPARAMETERIIVPROC glad_glTexParameterIiv = NULL;
+PFNGLTEXPARAMETERIUIVPROC glad_glTexParameterIuiv = NULL;
+PFNGLTEXPARAMETERFPROC glad_glTexParameterf = NULL;
+PFNGLTEXPARAMETERFVPROC glad_glTexParameterfv = NULL;
+PFNGLTEXPARAMETERIPROC glad_glTexParameteri = NULL;
+PFNGLTEXPARAMETERIVPROC glad_glTexParameteriv = NULL;
+PFNGLTEXSUBIMAGE1DPROC glad_glTexSubImage1D = NULL;
+PFNGLTEXSUBIMAGE2DPROC glad_glTexSubImage2D = NULL;
+PFNGLTEXSUBIMAGE3DPROC glad_glTexSubImage3D = NULL;
+PFNGLTRANSFORMFEEDBACKVARYINGSPROC glad_glTransformFeedbackVaryings = NULL;
+PFNGLUNIFORM1FPROC glad_glUniform1f = NULL;
+PFNGLUNIFORM1FVPROC glad_glUniform1fv = NULL;
+PFNGLUNIFORM1IPROC glad_glUniform1i = NULL;
+PFNGLUNIFORM1IVPROC glad_glUniform1iv = NULL;
+PFNGLUNIFORM1UIPROC glad_glUniform1ui = NULL;
+PFNGLUNIFORM1UIVPROC glad_glUniform1uiv = NULL;
+PFNGLUNIFORM2FPROC glad_glUniform2f = NULL;
+PFNGLUNIFORM2FVPROC glad_glUniform2fv = NULL;
+PFNGLUNIFORM2IPROC glad_glUniform2i = NULL;
+PFNGLUNIFORM2IVPROC glad_glUniform2iv = NULL;
+PFNGLUNIFORM2UIPROC glad_glUniform2ui = NULL;
+PFNGLUNIFORM2UIVPROC glad_glUniform2uiv = NULL;
+PFNGLUNIFORM3FPROC glad_glUniform3f = NULL;
+PFNGLUNIFORM3FVPROC glad_glUniform3fv = NULL;
+PFNGLUNIFORM3IPROC glad_glUniform3i = NULL;
+PFNGLUNIFORM3IVPROC glad_glUniform3iv = NULL;
+PFNGLUNIFORM3UIPROC glad_glUniform3ui = NULL;
+PFNGLUNIFORM3UIVPROC glad_glUniform3uiv = NULL;
+PFNGLUNIFORM4FPROC glad_glUniform4f = NULL;
+PFNGLUNIFORM4FVPROC glad_glUniform4fv = NULL;
+PFNGLUNIFORM4IPROC glad_glUniform4i = NULL;
+PFNGLUNIFORM4IVPROC glad_glUniform4iv = NULL;
+PFNGLUNIFORM4UIPROC glad_glUniform4ui = NULL;
+PFNGLUNIFORM4UIVPROC glad_glUniform4uiv = NULL;
+PFNGLUNIFORMBLOCKBINDINGPROC glad_glUniformBlockBinding = NULL;
+PFNGLUNIFORMMATRIX2FVPROC glad_glUniformMatrix2fv = NULL;
+PFNGLUNIFORMMATRIX2X3FVPROC glad_glUniformMatrix2x3fv = NULL;
+PFNGLUNIFORMMATRIX2X4FVPROC glad_glUniformMatrix2x4fv = NULL;
+PFNGLUNIFORMMATRIX3FVPROC glad_glUniformMatrix3fv = NULL;
+PFNGLUNIFORMMATRIX3X2FVPROC glad_glUniformMatrix3x2fv = NULL;
+PFNGLUNIFORMMATRIX3X4FVPROC glad_glUniformMatrix3x4fv = NULL;
+PFNGLUNIFORMMATRIX4FVPROC glad_glUniformMatrix4fv = NULL;
+PFNGLUNIFORMMATRIX4X2FVPROC glad_glUniformMatrix4x2fv = NULL;
+PFNGLUNIFORMMATRIX4X3FVPROC glad_glUniformMatrix4x3fv = NULL;
+PFNGLUNMAPBUFFERPROC glad_glUnmapBuffer = NULL;
+PFNGLUSEPROGRAMPROC glad_glUseProgram = NULL;
+PFNGLVALIDATEPROGRAMPROC glad_glValidateProgram = NULL;
+PFNGLVERTEXATTRIB1DPROC glad_glVertexAttrib1d = NULL;
+PFNGLVERTEXATTRIB1DVPROC glad_glVertexAttrib1dv = NULL;
+PFNGLVERTEXATTRIB1FPROC glad_glVertexAttrib1f = NULL;
+PFNGLVERTEXATTRIB1FVPROC glad_glVertexAttrib1fv = NULL;
+PFNGLVERTEXATTRIB1SPROC glad_glVertexAttrib1s = NULL;
+PFNGLVERTEXATTRIB1SVPROC glad_glVertexAttrib1sv = NULL;
+PFNGLVERTEXATTRIB2DPROC glad_glVertexAttrib2d = NULL;
+PFNGLVERTEXATTRIB2DVPROC glad_glVertexAttrib2dv = NULL;
+PFNGLVERTEXATTRIB2FPROC glad_glVertexAttrib2f = NULL;
+PFNGLVERTEXATTRIB2FVPROC glad_glVertexAttrib2fv = NULL;
+PFNGLVERTEXATTRIB2SPROC glad_glVertexAttrib2s = NULL;
+PFNGLVERTEXATTRIB2SVPROC glad_glVertexAttrib2sv = NULL;
+PFNGLVERTEXATTRIB3DPROC glad_glVertexAttrib3d = NULL;
+PFNGLVERTEXATTRIB3DVPROC glad_glVertexAttrib3dv = NULL;
+PFNGLVERTEXATTRIB3FPROC glad_glVertexAttrib3f = NULL;
+PFNGLVERTEXATTRIB3FVPROC glad_glVertexAttrib3fv = NULL;
+PFNGLVERTEXATTRIB3SPROC glad_glVertexAttrib3s = NULL;
+PFNGLVERTEXATTRIB3SVPROC glad_glVertexAttrib3sv = NULL;
+PFNGLVERTEXATTRIB4NBVPROC glad_glVertexAttrib4Nbv = NULL;
+PFNGLVERTEXATTRIB4NIVPROC glad_glVertexAttrib4Niv = NULL;
+PFNGLVERTEXATTRIB4NSVPROC glad_glVertexAttrib4Nsv = NULL;
+PFNGLVERTEXATTRIB4NUBPROC glad_glVertexAttrib4Nub = NULL;
+PFNGLVERTEXATTRIB4NUBVPROC glad_glVertexAttrib4Nubv = NULL;
+PFNGLVERTEXATTRIB4NUIVPROC glad_glVertexAttrib4Nuiv = NULL;
+PFNGLVERTEXATTRIB4NUSVPROC glad_glVertexAttrib4Nusv = NULL;
+PFNGLVERTEXATTRIB4BVPROC glad_glVertexAttrib4bv = NULL;
+PFNGLVERTEXATTRIB4DPROC glad_glVertexAttrib4d = NULL;
+PFNGLVERTEXATTRIB4DVPROC glad_glVertexAttrib4dv = NULL;
+PFNGLVERTEXATTRIB4FPROC glad_glVertexAttrib4f = NULL;
+PFNGLVERTEXATTRIB4FVPROC glad_glVertexAttrib4fv = NULL;
+PFNGLVERTEXATTRIB4IVPROC glad_glVertexAttrib4iv = NULL;
+PFNGLVERTEXATTRIB4SPROC glad_glVertexAttrib4s = NULL;
+PFNGLVERTEXATTRIB4SVPROC glad_glVertexAttrib4sv = NULL;
+PFNGLVERTEXATTRIB4UBVPROC glad_glVertexAttrib4ubv = NULL;
+PFNGLVERTEXATTRIB4UIVPROC glad_glVertexAttrib4uiv = NULL;
+PFNGLVERTEXATTRIB4USVPROC glad_glVertexAttrib4usv = NULL;
+PFNGLVERTEXATTRIBDIVISORPROC glad_glVertexAttribDivisor = NULL;
+PFNGLVERTEXATTRIBI1IPROC glad_glVertexAttribI1i = NULL;
+PFNGLVERTEXATTRIBI1IVPROC glad_glVertexAttribI1iv = NULL;
+PFNGLVERTEXATTRIBI1UIPROC glad_glVertexAttribI1ui = NULL;
+PFNGLVERTEXATTRIBI1UIVPROC glad_glVertexAttribI1uiv = NULL;
+PFNGLVERTEXATTRIBI2IPROC glad_glVertexAttribI2i = NULL;
+PFNGLVERTEXATTRIBI2IVPROC glad_glVertexAttribI2iv = NULL;
+PFNGLVERTEXATTRIBI2UIPROC glad_glVertexAttribI2ui = NULL;
+PFNGLVERTEXATTRIBI2UIVPROC glad_glVertexAttribI2uiv = NULL;
+PFNGLVERTEXATTRIBI3IPROC glad_glVertexAttribI3i = NULL;
+PFNGLVERTEXATTRIBI3IVPROC glad_glVertexAttribI3iv = NULL;
+PFNGLVERTEXATTRIBI3UIPROC glad_glVertexAttribI3ui = NULL;
+PFNGLVERTEXATTRIBI3UIVPROC glad_glVertexAttribI3uiv = NULL;
+PFNGLVERTEXATTRIBI4BVPROC glad_glVertexAttribI4bv = NULL;
+PFNGLVERTEXATTRIBI4IPROC glad_glVertexAttribI4i = NULL;
+PFNGLVERTEXATTRIBI4IVPROC glad_glVertexAttribI4iv = NULL;
+PFNGLVERTEXATTRIBI4SVPROC glad_glVertexAttribI4sv = NULL;
+PFNGLVERTEXATTRIBI4UBVPROC glad_glVertexAttribI4ubv = NULL;
+PFNGLVERTEXATTRIBI4UIPROC glad_glVertexAttribI4ui = NULL;
+PFNGLVERTEXATTRIBI4UIVPROC glad_glVertexAttribI4uiv = NULL;
+PFNGLVERTEXATTRIBI4USVPROC glad_glVertexAttribI4usv = NULL;
+PFNGLVERTEXATTRIBIPOINTERPROC glad_glVertexAttribIPointer = NULL;
+PFNGLVERTEXATTRIBP1UIPROC glad_glVertexAttribP1ui = NULL;
+PFNGLVERTEXATTRIBP1UIVPROC glad_glVertexAttribP1uiv = NULL;
+PFNGLVERTEXATTRIBP2UIPROC glad_glVertexAttribP2ui = NULL;
+PFNGLVERTEXATTRIBP2UIVPROC glad_glVertexAttribP2uiv = NULL;
+PFNGLVERTEXATTRIBP3UIPROC glad_glVertexAttribP3ui = NULL;
+PFNGLVERTEXATTRIBP3UIVPROC glad_glVertexAttribP3uiv = NULL;
+PFNGLVERTEXATTRIBP4UIPROC glad_glVertexAttribP4ui = NULL;
+PFNGLVERTEXATTRIBP4UIVPROC glad_glVertexAttribP4uiv = NULL;
+PFNGLVERTEXATTRIBPOINTERPROC glad_glVertexAttribPointer = NULL;
+PFNGLVIEWPORTPROC glad_glViewport = NULL;
+PFNGLWAITSYNCPROC glad_glWaitSync = NULL;
+
+
+static void glad_gl_load_GL_VERSION_1_0( GLADuserptrloadfunc load, void* userptr) {
+    if(!GLAD_GL_VERSION_1_0) return;
+    glad_glBlendFunc = (PFNGLBLENDFUNCPROC) load(userptr, "glBlendFunc");
+    glad_glClear = (PFNGLCLEARPROC) load(userptr, "glClear");
+    glad_glClearColor = (PFNGLCLEARCOLORPROC) load(userptr, "glClearColor");
+    glad_glClearDepth = (PFNGLCLEARDEPTHPROC) load(userptr, "glClearDepth");
+    glad_glClearStencil = (PFNGLCLEARSTENCILPROC) load(userptr, "glClearStencil");
+    glad_glColorMask = (PFNGLCOLORMASKPROC) load(userptr, "glColorMask");
+    glad_glCullFace = (PFNGLCULLFACEPROC) load(userptr, "glCullFace");
+    glad_glDepthFunc = (PFNGLDEPTHFUNCPROC) load(userptr, "glDepthFunc");
+    glad_glDepthMask = (PFNGLDEPTHMASKPROC) load(userptr, "glDepthMask");
+    glad_glDepthRange = (PFNGLDEPTHRANGEPROC) load(userptr, "glDepthRange");
+    glad_glDisable = (PFNGLDISABLEPROC) load(userptr, "glDisable");
+    glad_glDrawBuffer = (PFNGLDRAWBUFFERPROC) load(userptr, "glDrawBuffer");
+    glad_glEnable = (PFNGLENABLEPROC) load(userptr, "glEnable");
+    glad_glFinish = (PFNGLFINISHPROC) load(userptr, "glFinish");
+    glad_glFlush = (PFNGLFLUSHPROC) load(userptr, "glFlush");
+    glad_glFrontFace = (PFNGLFRONTFACEPROC) load(userptr, "glFrontFace");
+    glad_glGetBooleanv = (PFNGLGETBOOLEANVPROC) load(userptr, "glGetBooleanv");
+    glad_glGetDoublev = (PFNGLGETDOUBLEVPROC) load(userptr, "glGetDoublev");
+    glad_glGetError = (PFNGLGETERRORPROC) load(userptr, "glGetError");
+    glad_glGetFloatv = (PFNGLGETFLOATVPROC) load(userptr, "glGetFloatv");
+    glad_glGetIntegerv = (PFNGLGETINTEGERVPROC) load(userptr, "glGetIntegerv");
+    glad_glGetString = (PFNGLGETSTRINGPROC) load(userptr, "glGetString");
+    glad_glGetTexImage = (PFNGLGETTEXIMAGEPROC) load(userptr, "glGetTexImage");
+    glad_glGetTexLevelParameterfv = (PFNGLGETTEXLEVELPARAMETERFVPROC) load(userptr, "glGetTexLevelParameterfv");
+    glad_glGetTexLevelParameteriv = (PFNGLGETTEXLEVELPARAMETERIVPROC) load(userptr, "glGetTexLevelParameteriv");
+    glad_glGetTexParameterfv = (PFNGLGETTEXPARAMETERFVPROC) load(userptr, "glGetTexParameterfv");
+    glad_glGetTexParameteriv = (PFNGLGETTEXPARAMETERIVPROC) load(userptr, "glGetTexParameteriv");
+    glad_glHint = (PFNGLHINTPROC) load(userptr, "glHint");
+    glad_glIsEnabled = (PFNGLISENABLEDPROC) load(userptr, "glIsEnabled");
+    glad_glLineWidth = (PFNGLLINEWIDTHPROC) load(userptr, "glLineWidth");
+    glad_glLogicOp = (PFNGLLOGICOPPROC) load(userptr, "glLogicOp");
+    glad_glPixelStoref = (PFNGLPIXELSTOREFPROC) load(userptr, "glPixelStoref");
+    glad_glPixelStorei = (PFNGLPIXELSTOREIPROC) load(userptr, "glPixelStorei");
+    glad_glPointSize = (PFNGLPOINTSIZEPROC) load(userptr, "glPointSize");
+    glad_glPolygonMode = (PFNGLPOLYGONMODEPROC) load(userptr, "glPolygonMode");
+    glad_glReadBuffer = (PFNGLREADBUFFERPROC) load(userptr, "glReadBuffer");
+    glad_glReadPixels = (PFNGLREADPIXELSPROC) load(userptr, "glReadPixels");
+    glad_glScissor = (PFNGLSCISSORPROC) load(userptr, "glScissor");
+    glad_glStencilFunc = (PFNGLSTENCILFUNCPROC) load(userptr, "glStencilFunc");
+    glad_glStencilMask = (PFNGLSTENCILMASKPROC) load(userptr, "glStencilMask");
+    glad_glStencilOp = (PFNGLSTENCILOPPROC) load(userptr, "glStencilOp");
+    glad_glTexImage1D = (PFNGLTEXIMAGE1DPROC) load(userptr, "glTexImage1D");
+    glad_glTexImage2D = (PFNGLTEXIMAGE2DPROC) load(userptr, "glTexImage2D");
+    glad_glTexParameterf = (PFNGLTEXPARAMETERFPROC) load(userptr, "glTexParameterf");
+    glad_glTexParameterfv = (PFNGLTEXPARAMETERFVPROC) load(userptr, "glTexParameterfv");
+    glad_glTexParameteri = (PFNGLTEXPARAMETERIPROC) load(userptr, "glTexParameteri");
+    glad_glTexParameteriv = (PFNGLTEXPARAMETERIVPROC) load(userptr, "glTexParameteriv");
+    glad_glViewport = (PFNGLVIEWPORTPROC) load(userptr, "glViewport");
+}
+static void glad_gl_load_GL_VERSION_1_1( GLADuserptrloadfunc load, void* userptr) {
+    if(!GLAD_GL_VERSION_1_1) return;
+    glad_glBindTexture = (PFNGLBINDTEXTUREPROC) load(userptr, "glBindTexture");
+    glad_glCopyTexImage1D = (PFNGLCOPYTEXIMAGE1DPROC) load(userptr, "glCopyTexImage1D");
+    glad_glCopyTexImage2D = (PFNGLCOPYTEXIMAGE2DPROC) load(userptr, "glCopyTexImage2D");
+    glad_glCopyTexSubImage1D = (PFNGLCOPYTEXSUBIMAGE1DPROC) load(userptr, "glCopyTexSubImage1D");
+    glad_glCopyTexSubImage2D = (PFNGLCOPYTEXSUBIMAGE2DPROC) load(userptr, "glCopyTexSubImage2D");
+    glad_glDeleteTextures = (PFNGLDELETETEXTURESPROC) load(userptr, "glDeleteTextures");
+    glad_glDrawArrays = (PFNGLDRAWARRAYSPROC) load(userptr, "glDrawArrays");
+    glad_glDrawElements = (PFNGLDRAWELEMENTSPROC) load(userptr, "glDrawElements");
+    glad_glGenTextures = (PFNGLGENTEXTURESPROC) load(userptr, "glGenTextures");
+    glad_glIsTexture = (PFNGLISTEXTUREPROC) load(userptr, "glIsTexture");
+    glad_glPolygonOffset = (PFNGLPOLYGONOFFSETPROC) load(userptr, "glPolygonOffset");
+    glad_glTexSubImage1D = (PFNGLTEXSUBIMAGE1DPROC) load(userptr, "glTexSubImage1D");
+    glad_glTexSubImage2D = (PFNGLTEXSUBIMAGE2DPROC) load(userptr, "glTexSubImage2D");
+}
+static void glad_gl_load_GL_VERSION_1_2( GLADuserptrloadfunc load, void* userptr) {
+    if(!GLAD_GL_VERSION_1_2) return;
+    glad_glCopyTexSubImage3D = (PFNGLCOPYTEXSUBIMAGE3DPROC) load(userptr, "glCopyTexSubImage3D");
+    glad_glDrawRangeElements = (PFNGLDRAWRANGEELEMENTSPROC) load(userptr, "glDrawRangeElements");
+    glad_glTexImage3D = (PFNGLTEXIMAGE3DPROC) load(userptr, "glTexImage3D");
+    glad_glTexSubImage3D = (PFNGLTEXSUBIMAGE3DPROC) load(userptr, "glTexSubImage3D");
+}
+static void glad_gl_load_GL_VERSION_1_3( GLADuserptrloadfunc load, void* userptr) {
+    if(!GLAD_GL_VERSION_1_3) return;
+    glad_glActiveTexture = (PFNGLACTIVETEXTUREPROC) load(userptr, "glActiveTexture");
+    glad_glCompressedTexImage1D = (PFNGLCOMPRESSEDTEXIMAGE1DPROC) load(userptr, "glCompressedTexImage1D");
+    glad_glCompressedTexImage2D = (PFNGLCOMPRESSEDTEXIMAGE2DPROC) load(userptr, "glCompressedTexImage2D");
+    glad_glCompressedTexImage3D = (PFNGLCOMPRESSEDTEXIMAGE3DPROC) load(userptr, "glCompressedTexImage3D");
+    glad_glCompressedTexSubImage1D = (PFNGLCOMPRESSEDTEXSUBIMAGE1DPROC) load(userptr, "glCompressedTexSubImage1D");
+    glad_glCompressedTexSubImage2D = (PFNGLCOMPRESSEDTEXSUBIMAGE2DPROC) load(userptr, "glCompressedTexSubImage2D");
+    glad_glCompressedTexSubImage3D = (PFNGLCOMPRESSEDTEXSUBIMAGE3DPROC) load(userptr, "glCompressedTexSubImage3D");
+    glad_glGetCompressedTexImage = (PFNGLGETCOMPRESSEDTEXIMAGEPROC) load(userptr, "glGetCompressedTexImage");
+    glad_glSampleCoverage = (PFNGLSAMPLECOVERAGEPROC) load(userptr, "glSampleCoverage");
+}
+static void glad_gl_load_GL_VERSION_1_4( GLADuserptrloadfunc load, void* userptr) {
+    if(!GLAD_GL_VERSION_1_4) return;
+    glad_glBlendColor = (PFNGLBLENDCOLORPROC) load(userptr, "glBlendColor");
+    glad_glBlendEquation = (PFNGLBLENDEQUATIONPROC) load(userptr, "glBlendEquation");
+    glad_glBlendFuncSeparate = (PFNGLBLENDFUNCSEPARATEPROC) load(userptr, "glBlendFuncSeparate");
+    glad_glMultiDrawArrays = (PFNGLMULTIDRAWARRAYSPROC) load(userptr, "glMultiDrawArrays");
+    glad_glMultiDrawElements = (PFNGLMULTIDRAWELEMENTSPROC) load(userptr, "glMultiDrawElements");
+    glad_glPointParameterf = (PFNGLPOINTPARAMETERFPROC) load(userptr, "glPointParameterf");
+    glad_glPointParameterfv = (PFNGLPOINTPARAMETERFVPROC) load(userptr, "glPointParameterfv");
+    glad_glPointParameteri = (PFNGLPOINTPARAMETERIPROC) load(userptr, "glPointParameteri");
+    glad_glPointParameteriv = (PFNGLPOINTPARAMETERIVPROC) load(userptr, "glPointParameteriv");
+}
+static void glad_gl_load_GL_VERSION_1_5( GLADuserptrloadfunc load, void* userptr) {
+    if(!GLAD_GL_VERSION_1_5) return;
+    glad_glBeginQuery = (PFNGLBEGINQUERYPROC) load(userptr, "glBeginQuery");
+    glad_glBindBuffer = (PFNGLBINDBUFFERPROC) load(userptr, "glBindBuffer");
+    glad_glBufferData = (PFNGLBUFFERDATAPROC) load(userptr, "glBufferData");
+    glad_glBufferSubData = (PFNGLBUFFERSUBDATAPROC) load(userptr, "glBufferSubData");
+    glad_glDeleteBuffers = (PFNGLDELETEBUFFERSPROC) load(userptr, "glDeleteBuffers");
+    glad_glDeleteQueries = (PFNGLDELETEQUERIESPROC) load(userptr, "glDeleteQueries");
+    glad_glEndQuery = (PFNGLENDQUERYPROC) load(userptr, "glEndQuery");
+    glad_glGenBuffers = (PFNGLGENBUFFERSPROC) load(userptr, "glGenBuffers");
+    glad_glGenQueries = (PFNGLGENQUERIESPROC) load(userptr, "glGenQueries");
+    glad_glGetBufferParameteriv = (PFNGLGETBUFFERPARAMETERIVPROC) load(userptr, "glGetBufferParameteriv");
+    glad_glGetBufferPointerv = (PFNGLGETBUFFERPOINTERVPROC) load(userptr, "glGetBufferPointerv");
+    glad_glGetBufferSubData = (PFNGLGETBUFFERSUBDATAPROC) load(userptr, "glGetBufferSubData");
+    glad_glGetQueryObjectiv = (PFNGLGETQUERYOBJECTIVPROC) load(userptr, "glGetQueryObjectiv");
+    glad_glGetQueryObjectuiv = (PFNGLGETQUERYOBJECTUIVPROC) load(userptr, "glGetQueryObjectuiv");
+    glad_glGetQueryiv = (PFNGLGETQUERYIVPROC) load(userptr, "glGetQueryiv");
+    glad_glIsBuffer = (PFNGLISBUFFERPROC) load(userptr, "glIsBuffer");
+    glad_glIsQuery = (PFNGLISQUERYPROC) load(userptr, "glIsQuery");
+    glad_glMapBuffer = (PFNGLMAPBUFFERPROC) load(userptr, "glMapBuffer");
+    glad_glUnmapBuffer = (PFNGLUNMAPBUFFERPROC) load(userptr, "glUnmapBuffer");
+}
+static void glad_gl_load_GL_VERSION_2_0( GLADuserptrloadfunc load, void* userptr) {
+    if(!GLAD_GL_VERSION_2_0) return;
+    glad_glAttachShader = (PFNGLATTACHSHADERPROC) load(userptr, "glAttachShader");
+    glad_glBindAttribLocation = (PFNGLBINDATTRIBLOCATIONPROC) load(userptr, "glBindAttribLocation");
+    glad_glBlendEquationSeparate = (PFNGLBLENDEQUATIONSEPARATEPROC) load(userptr, "glBlendEquationSeparate");
+    glad_glCompileShader = (PFNGLCOMPILESHADERPROC) load(userptr, "glCompileShader");
+    glad_glCreateProgram = (PFNGLCREATEPROGRAMPROC) load(userptr, "glCreateProgram");
+    glad_glCreateShader = (PFNGLCREATESHADERPROC) load(userptr, "glCreateShader");
+    glad_glDeleteProgram = (PFNGLDELETEPROGRAMPROC) load(userptr, "glDeleteProgram");
+    glad_glDeleteShader = (PFNGLDELETESHADERPROC) load(userptr, "glDeleteShader");
+    glad_glDetachShader = (PFNGLDETACHSHADERPROC) load(userptr, "glDetachShader");
+    glad_glDisableVertexAttribArray = (PFNGLDISABLEVERTEXATTRIBARRAYPROC) load(userptr, "glDisableVertexAttribArray");
+    glad_glDrawBuffers = (PFNGLDRAWBUFFERSPROC) load(userptr, "glDrawBuffers");
+    glad_glEnableVertexAttribArray = (PFNGLENABLEVERTEXATTRIBARRAYPROC) load(userptr, "glEnableVertexAttribArray");
+    glad_glGetActiveAttrib = (PFNGLGETACTIVEATTRIBPROC) load(userptr, "glGetActiveAttrib");
+    glad_glGetActiveUniform = (PFNGLGETACTIVEUNIFORMPROC) load(userptr, "glGetActiveUniform");
+    glad_glGetAttachedShaders = (PFNGLGETATTACHEDSHADERSPROC) load(userptr, "glGetAttachedShaders");
+    glad_glGetAttribLocation = (PFNGLGETATTRIBLOCATIONPROC) load(userptr, "glGetAttribLocation");
+    glad_glGetProgramInfoLog = (PFNGLGETPROGRAMINFOLOGPROC) load(userptr, "glGetProgramInfoLog");
+    glad_glGetProgramiv = (PFNGLGETPROGRAMIVPROC) load(userptr, "glGetProgramiv");
+    glad_glGetShaderInfoLog = (PFNGLGETSHADERINFOLOGPROC) load(userptr, "glGetShaderInfoLog");
+    glad_glGetShaderSource = (PFNGLGETSHADERSOURCEPROC) load(userptr, "glGetShaderSource");
+    glad_glGetShaderiv = (PFNGLGETSHADERIVPROC) load(userptr, "glGetShaderiv");
+    glad_glGetUniformLocation = (PFNGLGETUNIFORMLOCATIONPROC) load(userptr, "glGetUniformLocation");
+    glad_glGetUniformfv = (PFNGLGETUNIFORMFVPROC) load(userptr, "glGetUniformfv");
+    glad_glGetUniformiv = (PFNGLGETUNIFORMIVPROC) load(userptr, "glGetUniformiv");
+    glad_glGetVertexAttribPointerv = (PFNGLGETVERTEXATTRIBPOINTERVPROC) load(userptr, "glGetVertexAttribPointerv");
+    glad_glGetVertexAttribdv = (PFNGLGETVERTEXATTRIBDVPROC) load(userptr, "glGetVertexAttribdv");
+    glad_glGetVertexAttribfv = (PFNGLGETVERTEXATTRIBFVPROC) load(userptr, "glGetVertexAttribfv");
+    glad_glGetVertexAttribiv = (PFNGLGETVERTEXATTRIBIVPROC) load(userptr, "glGetVertexAttribiv");
+    glad_glIsProgram = (PFNGLISPROGRAMPROC) load(userptr, "glIsProgram");
+    glad_glIsShader = (PFNGLISSHADERPROC) load(userptr, "glIsShader");
+    glad_glLinkProgram = (PFNGLLINKPROGRAMPROC) load(userptr, "glLinkProgram");
+    glad_glShaderSource = (PFNGLSHADERSOURCEPROC) load(userptr, "glShaderSource");
+    glad_glStencilFuncSeparate = (PFNGLSTENCILFUNCSEPARATEPROC) load(userptr, "glStencilFuncSeparate");
+    glad_glStencilMaskSeparate = (PFNGLSTENCILMASKSEPARATEPROC) load(userptr, "glStencilMaskSeparate");
+    glad_glStencilOpSeparate = (PFNGLSTENCILOPSEPARATEPROC) load(userptr, "glStencilOpSeparate");
+    glad_glUniform1f = (PFNGLUNIFORM1FPROC) load(userptr, "glUniform1f");
+    glad_glUniform1fv = (PFNGLUNIFORM1FVPROC) load(userptr, "glUniform1fv");
+    glad_glUniform1i = (PFNGLUNIFORM1IPROC) load(userptr, "glUniform1i");
+    glad_glUniform1iv = (PFNGLUNIFORM1IVPROC) load(userptr, "glUniform1iv");
+    glad_glUniform2f = (PFNGLUNIFORM2FPROC) load(userptr, "glUniform2f");
+    glad_glUniform2fv = (PFNGLUNIFORM2FVPROC) load(userptr, "glUniform2fv");
+    glad_glUniform2i = (PFNGLUNIFORM2IPROC) load(userptr, "glUniform2i");
+    glad_glUniform2iv = (PFNGLUNIFORM2IVPROC) load(userptr, "glUniform2iv");
+    glad_glUniform3f = (PFNGLUNIFORM3FPROC) load(userptr, "glUniform3f");
+    glad_glUniform3fv = (PFNGLUNIFORM3FVPROC) load(userptr, "glUniform3fv");
+    glad_glUniform3i = (PFNGLUNIFORM3IPROC) load(userptr, "glUniform3i");
+    glad_glUniform3iv = (PFNGLUNIFORM3IVPROC) load(userptr, "glUniform3iv");
+    glad_glUniform4f = (PFNGLUNIFORM4FPROC) load(userptr, "glUniform4f");
+    glad_glUniform4fv = (PFNGLUNIFORM4FVPROC) load(userptr, "glUniform4fv");
+    glad_glUniform4i = (PFNGLUNIFORM4IPROC) load(userptr, "glUniform4i");
+    glad_glUniform4iv = (PFNGLUNIFORM4IVPROC) load(userptr, "glUniform4iv");
+    glad_glUniformMatrix2fv = (PFNGLUNIFORMMATRIX2FVPROC) load(userptr, "glUniformMatrix2fv");
+    glad_glUniformMatrix3fv = (PFNGLUNIFORMMATRIX3FVPROC) load(userptr, "glUniformMatrix3fv");
+    glad_glUniformMatrix4fv = (PFNGLUNIFORMMATRIX4FVPROC) load(userptr, "glUniformMatrix4fv");
+    glad_glUseProgram = (PFNGLUSEPROGRAMPROC) load(userptr, "glUseProgram");
+    glad_glValidateProgram = (PFNGLVALIDATEPROGRAMPROC) load(userptr, "glValidateProgram");
+    glad_glVertexAttrib1d = (PFNGLVERTEXATTRIB1DPROC) load(userptr, "glVertexAttrib1d");
+    glad_glVertexAttrib1dv = (PFNGLVERTEXATTRIB1DVPROC) load(userptr, "glVertexAttrib1dv");
+    glad_glVertexAttrib1f = (PFNGLVERTEXATTRIB1FPROC) load(userptr, "glVertexAttrib1f");
+    glad_glVertexAttrib1fv = (PFNGLVERTEXATTRIB1FVPROC) load(userptr, "glVertexAttrib1fv");
+    glad_glVertexAttrib1s = (PFNGLVERTEXATTRIB1SPROC) load(userptr, "glVertexAttrib1s");
+    glad_glVertexAttrib1sv = (PFNGLVERTEXATTRIB1SVPROC) load(userptr, "glVertexAttrib1sv");
+    glad_glVertexAttrib2d = (PFNGLVERTEXATTRIB2DPROC) load(userptr, "glVertexAttrib2d");
+    glad_glVertexAttrib2dv = (PFNGLVERTEXATTRIB2DVPROC) load(userptr, "glVertexAttrib2dv");
+    glad_glVertexAttrib2f = (PFNGLVERTEXATTRIB2FPROC) load(userptr, "glVertexAttrib2f");
+    glad_glVertexAttrib2fv = (PFNGLVERTEXATTRIB2FVPROC) load(userptr, "glVertexAttrib2fv");
+    glad_glVertexAttrib2s = (PFNGLVERTEXATTRIB2SPROC) load(userptr, "glVertexAttrib2s");
+    glad_glVertexAttrib2sv = (PFNGLVERTEXATTRIB2SVPROC) load(userptr, "glVertexAttrib2sv");
+    glad_glVertexAttrib3d = (PFNGLVERTEXATTRIB3DPROC) load(userptr, "glVertexAttrib3d");
+    glad_glVertexAttrib3dv = (PFNGLVERTEXATTRIB3DVPROC) load(userptr, "glVertexAttrib3dv");
+    glad_glVertexAttrib3f = (PFNGLVERTEXATTRIB3FPROC) load(userptr, "glVertexAttrib3f");
+    glad_glVertexAttrib3fv = (PFNGLVERTEXATTRIB3FVPROC) load(userptr, "glVertexAttrib3fv");
+    glad_glVertexAttrib3s = (PFNGLVERTEXATTRIB3SPROC) load(userptr, "glVertexAttrib3s");
+    glad_glVertexAttrib3sv = (PFNGLVERTEXATTRIB3SVPROC) load(userptr, "glVertexAttrib3sv");
+    glad_glVertexAttrib4Nbv = (PFNGLVERTEXATTRIB4NBVPROC) load(userptr, "glVertexAttrib4Nbv");
+    glad_glVertexAttrib4Niv = (PFNGLVERTEXATTRIB4NIVPROC) load(userptr, "glVertexAttrib4Niv");
+    glad_glVertexAttrib4Nsv = (PFNGLVERTEXATTRIB4NSVPROC) load(userptr, "glVertexAttrib4Nsv");
+    glad_glVertexAttrib4Nub = (PFNGLVERTEXATTRIB4NUBPROC) load(userptr, "glVertexAttrib4Nub");
+    glad_glVertexAttrib4Nubv = (PFNGLVERTEXATTRIB4NUBVPROC) load(userptr, "glVertexAttrib4Nubv");
+    glad_glVertexAttrib4Nuiv = (PFNGLVERTEXATTRIB4NUIVPROC) load(userptr, "glVertexAttrib4Nuiv");
+    glad_glVertexAttrib4Nusv = (PFNGLVERTEXATTRIB4NUSVPROC) load(userptr, "glVertexAttrib4Nusv");
+    glad_glVertexAttrib4bv = (PFNGLVERTEXATTRIB4BVPROC) load(userptr, "glVertexAttrib4bv");
+    glad_glVertexAttrib4d = (PFNGLVERTEXATTRIB4DPROC) load(userptr, "glVertexAttrib4d");
+    glad_glVertexAttrib4dv = (PFNGLVERTEXATTRIB4DVPROC) load(userptr, "glVertexAttrib4dv");
+    glad_glVertexAttrib4f = (PFNGLVERTEXATTRIB4FPROC) load(userptr, "glVertexAttrib4f");
+    glad_glVertexAttrib4fv = (PFNGLVERTEXATTRIB4FVPROC) load(userptr, "glVertexAttrib4fv");
+    glad_glVertexAttrib4iv = (PFNGLVERTEXATTRIB4IVPROC) load(userptr, "glVertexAttrib4iv");
+    glad_glVertexAttrib4s = (PFNGLVERTEXATTRIB4SPROC) load(userptr, "glVertexAttrib4s");
+    glad_glVertexAttrib4sv = (PFNGLVERTEXATTRIB4SVPROC) load(userptr, "glVertexAttrib4sv");
+    glad_glVertexAttrib4ubv = (PFNGLVERTEXATTRIB4UBVPROC) load(userptr, "glVertexAttrib4ubv");
+    glad_glVertexAttrib4uiv = (PFNGLVERTEXATTRIB4UIVPROC) load(userptr, "glVertexAttrib4uiv");
+    glad_glVertexAttrib4usv = (PFNGLVERTEXATTRIB4USVPROC) load(userptr, "glVertexAttrib4usv");
+    glad_glVertexAttribPointer = (PFNGLVERTEXATTRIBPOINTERPROC) load(userptr, "glVertexAttribPointer");
+}
+static void glad_gl_load_GL_VERSION_2_1( GLADuserptrloadfunc load, void* userptr) {
+    if(!GLAD_GL_VERSION_2_1) return;
+    glad_glUniformMatrix2x3fv = (PFNGLUNIFORMMATRIX2X3FVPROC) load(userptr, "glUniformMatrix2x3fv");
+    glad_glUniformMatrix2x4fv = (PFNGLUNIFORMMATRIX2X4FVPROC) load(userptr, "glUniformMatrix2x4fv");
+    glad_glUniformMatrix3x2fv = (PFNGLUNIFORMMATRIX3X2FVPROC) load(userptr, "glUniformMatrix3x2fv");
+    glad_glUniformMatrix3x4fv = (PFNGLUNIFORMMATRIX3X4FVPROC) load(userptr, "glUniformMatrix3x4fv");
+    glad_glUniformMatrix4x2fv = (PFNGLUNIFORMMATRIX4X2FVPROC) load(userptr, "glUniformMatrix4x2fv");
+    glad_glUniformMatrix4x3fv = (PFNGLUNIFORMMATRIX4X3FVPROC) load(userptr, "glUniformMatrix4x3fv");
+}
+static void glad_gl_load_GL_VERSION_3_0( GLADuserptrloadfunc load, void* userptr) {
+    if(!GLAD_GL_VERSION_3_0) return;
+    glad_glBeginConditionalRender = (PFNGLBEGINCONDITIONALRENDERPROC) load(userptr, "glBeginConditionalRender");
+    glad_glBeginTransformFeedback = (PFNGLBEGINTRANSFORMFEEDBACKPROC) load(userptr, "glBeginTransformFeedback");
+    glad_glBindBufferBase = (PFNGLBINDBUFFERBASEPROC) load(userptr, "glBindBufferBase");
+    glad_glBindBufferRange = (PFNGLBINDBUFFERRANGEPROC) load(userptr, "glBindBufferRange");
+    glad_glBindFragDataLocation = (PFNGLBINDFRAGDATALOCATIONPROC) load(userptr, "glBindFragDataLocation");
+    glad_glBindFramebuffer = (PFNGLBINDFRAMEBUFFERPROC) load(userptr, "glBindFramebuffer");
+    glad_glBindRenderbuffer = (PFNGLBINDRENDERBUFFERPROC) load(userptr, "glBindRenderbuffer");
+    glad_glBindVertexArray = (PFNGLBINDVERTEXARRAYPROC) load(userptr, "glBindVertexArray");
+    glad_glBlitFramebuffer = (PFNGLBLITFRAMEBUFFERPROC) load(userptr, "glBlitFramebuffer");
+    glad_glCheckFramebufferStatus = (PFNGLCHECKFRAMEBUFFERSTATUSPROC) load(userptr, "glCheckFramebufferStatus");
+    glad_glClampColor = (PFNGLCLAMPCOLORPROC) load(userptr, "glClampColor");
+    glad_glClearBufferfi = (PFNGLCLEARBUFFERFIPROC) load(userptr, "glClearBufferfi");
+    glad_glClearBufferfv = (PFNGLCLEARBUFFERFVPROC) load(userptr, "glClearBufferfv");
+    glad_glClearBufferiv = (PFNGLCLEARBUFFERIVPROC) load(userptr, "glClearBufferiv");
+    glad_glClearBufferuiv = (PFNGLCLEARBUFFERUIVPROC) load(userptr, "glClearBufferuiv");
+    glad_glColorMaski = (PFNGLCOLORMASKIPROC) load(userptr, "glColorMaski");
+    glad_glDeleteFramebuffers = (PFNGLDELETEFRAMEBUFFERSPROC) load(userptr, "glDeleteFramebuffers");
+    glad_glDeleteRenderbuffers = (PFNGLDELETERENDERBUFFERSPROC) load(userptr, "glDeleteRenderbuffers");
+    glad_glDeleteVertexArrays = (PFNGLDELETEVERTEXARRAYSPROC) load(userptr, "glDeleteVertexArrays");
+    glad_glDisablei = (PFNGLDISABLEIPROC) load(userptr, "glDisablei");
+    glad_glEnablei = (PFNGLENABLEIPROC) load(userptr, "glEnablei");
+    glad_glEndConditionalRender = (PFNGLENDCONDITIONALRENDERPROC) load(userptr, "glEndConditionalRender");
+    glad_glEndTransformFeedback = (PFNGLENDTRANSFORMFEEDBACKPROC) load(userptr, "glEndTransformFeedback");
+    glad_glFlushMappedBufferRange = (PFNGLFLUSHMAPPEDBUFFERRANGEPROC) load(userptr, "glFlushMappedBufferRange");
+    glad_glFramebufferRenderbuffer = (PFNGLFRAMEBUFFERRENDERBUFFERPROC) load(userptr, "glFramebufferRenderbuffer");
+    glad_glFramebufferTexture1D = (PFNGLFRAMEBUFFERTEXTURE1DPROC) load(userptr, "glFramebufferTexture1D");
+    glad_glFramebufferTexture2D = (PFNGLFRAMEBUFFERTEXTURE2DPROC) load(userptr, "glFramebufferTexture2D");
+    glad_glFramebufferTexture3D = (PFNGLFRAMEBUFFERTEXTURE3DPROC) load(userptr, "glFramebufferTexture3D");
+    glad_glFramebufferTextureLayer = (PFNGLFRAMEBUFFERTEXTURELAYERPROC) load(userptr, "glFramebufferTextureLayer");
+    glad_glGenFramebuffers = (PFNGLGENFRAMEBUFFERSPROC) load(userptr, "glGenFramebuffers");
+    glad_glGenRenderbuffers = (PFNGLGENRENDERBUFFERSPROC) load(userptr, "glGenRenderbuffers");
+    glad_glGenVertexArrays = (PFNGLGENVERTEXARRAYSPROC) load(userptr, "glGenVertexArrays");
+    glad_glGenerateMipmap = (PFNGLGENERATEMIPMAPPROC) load(userptr, "glGenerateMipmap");
+    glad_glGetBooleani_v = (PFNGLGETBOOLEANI_VPROC) load(userptr, "glGetBooleani_v");
+    glad_glGetFragDataLocation = (PFNGLGETFRAGDATALOCATIONPROC) load(userptr, "glGetFragDataLocation");
+    glad_glGetFramebufferAttachmentParameteriv = (PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVPROC) load(userptr, "glGetFramebufferAttachmentParameteriv");
+    glad_glGetIntegeri_v = (PFNGLGETINTEGERI_VPROC) load(userptr, "glGetIntegeri_v");
+    glad_glGetRenderbufferParameteriv = (PFNGLGETRENDERBUFFERPARAMETERIVPROC) load(userptr, "glGetRenderbufferParameteriv");
+    glad_glGetStringi = (PFNGLGETSTRINGIPROC) load(userptr, "glGetStringi");
+    glad_glGetTexParameterIiv = (PFNGLGETTEXPARAMETERIIVPROC) load(userptr, "glGetTexParameterIiv");
+    glad_glGetTexParameterIuiv = (PFNGLGETTEXPARAMETERIUIVPROC) load(userptr, "glGetTexParameterIuiv");
+    glad_glGetTransformFeedbackVarying = (PFNGLGETTRANSFORMFEEDBACKVARYINGPROC) load(userptr, "glGetTransformFeedbackVarying");
+    glad_glGetUniformuiv = (PFNGLGETUNIFORMUIVPROC) load(userptr, "glGetUniformuiv");
+    glad_glGetVertexAttribIiv = (PFNGLGETVERTEXATTRIBIIVPROC) load(userptr, "glGetVertexAttribIiv");
+    glad_glGetVertexAttribIuiv = (PFNGLGETVERTEXATTRIBIUIVPROC) load(userptr, "glGetVertexAttribIuiv");
+    glad_glIsEnabledi = (PFNGLISENABLEDIPROC) load(userptr, "glIsEnabledi");
+    glad_glIsFramebuffer = (PFNGLISFRAMEBUFFERPROC) load(userptr, "glIsFramebuffer");
+    glad_glIsRenderbuffer = (PFNGLISRENDERBUFFERPROC) load(userptr, "glIsRenderbuffer");
+    glad_glIsVertexArray = (PFNGLISVERTEXARRAYPROC) load(userptr, "glIsVertexArray");
+    glad_glMapBufferRange = (PFNGLMAPBUFFERRANGEPROC) load(userptr, "glMapBufferRange");
+    glad_glRenderbufferStorage = (PFNGLRENDERBUFFERSTORAGEPROC) load(userptr, "glRenderbufferStorage");
+    glad_glRenderbufferStorageMultisample = (PFNGLRENDERBUFFERSTORAGEMULTISAMPLEPROC) load(userptr, "glRenderbufferStorageMultisample");
+    glad_glTexParameterIiv = (PFNGLTEXPARAMETERIIVPROC) load(userptr, "glTexParameterIiv");
+    glad_glTexParameterIuiv = (PFNGLTEXPARAMETERIUIVPROC) load(userptr, "glTexParameterIuiv");
+    glad_glTransformFeedbackVaryings = (PFNGLTRANSFORMFEEDBACKVARYINGSPROC) load(userptr, "glTransformFeedbackVaryings");
+    glad_glUniform1ui = (PFNGLUNIFORM1UIPROC) load(userptr, "glUniform1ui");
+    glad_glUniform1uiv = (PFNGLUNIFORM1UIVPROC) load(userptr, "glUniform1uiv");
+    glad_glUniform2ui = (PFNGLUNIFORM2UIPROC) load(userptr, "glUniform2ui");
+    glad_glUniform2uiv = (PFNGLUNIFORM2UIVPROC) load(userptr, "glUniform2uiv");
+    glad_glUniform3ui = (PFNGLUNIFORM3UIPROC) load(userptr, "glUniform3ui");
+    glad_glUniform3uiv = (PFNGLUNIFORM3UIVPROC) load(userptr, "glUniform3uiv");
+    glad_glUniform4ui = (PFNGLUNIFORM4UIPROC) load(userptr, "glUniform4ui");
+    glad_glUniform4uiv = (PFNGLUNIFORM4UIVPROC) load(userptr, "glUniform4uiv");
+    glad_glVertexAttribI1i = (PFNGLVERTEXATTRIBI1IPROC) load(userptr, "glVertexAttribI1i");
+    glad_glVertexAttribI1iv = (PFNGLVERTEXATTRIBI1IVPROC) load(userptr, "glVertexAttribI1iv");
+    glad_glVertexAttribI1ui = (PFNGLVERTEXATTRIBI1UIPROC) load(userptr, "glVertexAttribI1ui");
+    glad_glVertexAttribI1uiv = (PFNGLVERTEXATTRIBI1UIVPROC) load(userptr, "glVertexAttribI1uiv");
+    glad_glVertexAttribI2i = (PFNGLVERTEXATTRIBI2IPROC) load(userptr, "glVertexAttribI2i");
+    glad_glVertexAttribI2iv = (PFNGLVERTEXATTRIBI2IVPROC) load(userptr, "glVertexAttribI2iv");
+    glad_glVertexAttribI2ui = (PFNGLVERTEXATTRIBI2UIPROC) load(userptr, "glVertexAttribI2ui");
+    glad_glVertexAttribI2uiv = (PFNGLVERTEXATTRIBI2UIVPROC) load(userptr, "glVertexAttribI2uiv");
+    glad_glVertexAttribI3i = (PFNGLVERTEXATTRIBI3IPROC) load(userptr, "glVertexAttribI3i");
+    glad_glVertexAttribI3iv = (PFNGLVERTEXATTRIBI3IVPROC) load(userptr, "glVertexAttribI3iv");
+    glad_glVertexAttribI3ui = (PFNGLVERTEXATTRIBI3UIPROC) load(userptr, "glVertexAttribI3ui");
+    glad_glVertexAttribI3uiv = (PFNGLVERTEXATTRIBI3UIVPROC) load(userptr, "glVertexAttribI3uiv");
+    glad_glVertexAttribI4bv = (PFNGLVERTEXATTRIBI4BVPROC) load(userptr, "glVertexAttribI4bv");
+    glad_glVertexAttribI4i = (PFNGLVERTEXATTRIBI4IPROC) load(userptr, "glVertexAttribI4i");
+    glad_glVertexAttribI4iv = (PFNGLVERTEXATTRIBI4IVPROC) load(userptr, "glVertexAttribI4iv");
+    glad_glVertexAttribI4sv = (PFNGLVERTEXATTRIBI4SVPROC) load(userptr, "glVertexAttribI4sv");
+    glad_glVertexAttribI4ubv = (PFNGLVERTEXATTRIBI4UBVPROC) load(userptr, "glVertexAttribI4ubv");
+    glad_glVertexAttribI4ui = (PFNGLVERTEXATTRIBI4UIPROC) load(userptr, "glVertexAttribI4ui");
+    glad_glVertexAttribI4uiv = (PFNGLVERTEXATTRIBI4UIVPROC) load(userptr, "glVertexAttribI4uiv");
+    glad_glVertexAttribI4usv = (PFNGLVERTEXATTRIBI4USVPROC) load(userptr, "glVertexAttribI4usv");
+    glad_glVertexAttribIPointer = (PFNGLVERTEXATTRIBIPOINTERPROC) load(userptr, "glVertexAttribIPointer");
+}
+static void glad_gl_load_GL_VERSION_3_1( GLADuserptrloadfunc load, void* userptr) {
+    if(!GLAD_GL_VERSION_3_1) return;
+    glad_glBindBufferBase = (PFNGLBINDBUFFERBASEPROC) load(userptr, "glBindBufferBase");
+    glad_glBindBufferRange = (PFNGLBINDBUFFERRANGEPROC) load(userptr, "glBindBufferRange");
+    glad_glCopyBufferSubData = (PFNGLCOPYBUFFERSUBDATAPROC) load(userptr, "glCopyBufferSubData");
+    glad_glDrawArraysInstanced = (PFNGLDRAWARRAYSINSTANCEDPROC) load(userptr, "glDrawArraysInstanced");
+    glad_glDrawElementsInstanced = (PFNGLDRAWELEMENTSINSTANCEDPROC) load(userptr, "glDrawElementsInstanced");
+    glad_glGetActiveUniformBlockName = (PFNGLGETACTIVEUNIFORMBLOCKNAMEPROC) load(userptr, "glGetActiveUniformBlockName");
+    glad_glGetActiveUniformBlockiv = (PFNGLGETACTIVEUNIFORMBLOCKIVPROC) load(userptr, "glGetActiveUniformBlockiv");
+    glad_glGetActiveUniformName = (PFNGLGETACTIVEUNIFORMNAMEPROC) load(userptr, "glGetActiveUniformName");
+    glad_glGetActiveUniformsiv = (PFNGLGETACTIVEUNIFORMSIVPROC) load(userptr, "glGetActiveUniformsiv");
+    glad_glGetIntegeri_v = (PFNGLGETINTEGERI_VPROC) load(userptr, "glGetIntegeri_v");
+    glad_glGetUniformBlockIndex = (PFNGLGETUNIFORMBLOCKINDEXPROC) load(userptr, "glGetUniformBlockIndex");
+    glad_glGetUniformIndices = (PFNGLGETUNIFORMINDICESPROC) load(userptr, "glGetUniformIndices");
+    glad_glPrimitiveRestartIndex = (PFNGLPRIMITIVERESTARTINDEXPROC) load(userptr, "glPrimitiveRestartIndex");
+    glad_glTexBuffer = (PFNGLTEXBUFFERPROC) load(userptr, "glTexBuffer");
+    glad_glUniformBlockBinding = (PFNGLUNIFORMBLOCKBINDINGPROC) load(userptr, "glUniformBlockBinding");
+}
+static void glad_gl_load_GL_VERSION_3_2( GLADuserptrloadfunc load, void* userptr) {
+    if(!GLAD_GL_VERSION_3_2) return;
+    glad_glClientWaitSync = (PFNGLCLIENTWAITSYNCPROC) load(userptr, "glClientWaitSync");
+    glad_glDeleteSync = (PFNGLDELETESYNCPROC) load(userptr, "glDeleteSync");
+    glad_glDrawElementsBaseVertex = (PFNGLDRAWELEMENTSBASEVERTEXPROC) load(userptr, "glDrawElementsBaseVertex");
+    glad_glDrawElementsInstancedBaseVertex = (PFNGLDRAWELEMENTSINSTANCEDBASEVERTEXPROC) load(userptr, "glDrawElementsInstancedBaseVertex");
+    glad_glDrawRangeElementsBaseVertex = (PFNGLDRAWRANGEELEMENTSBASEVERTEXPROC) load(userptr, "glDrawRangeElementsBaseVertex");
+    glad_glFenceSync = (PFNGLFENCESYNCPROC) load(userptr, "glFenceSync");
+    glad_glFramebufferTexture = (PFNGLFRAMEBUFFERTEXTUREPROC) load(userptr, "glFramebufferTexture");
+    glad_glGetBufferParameteri64v = (PFNGLGETBUFFERPARAMETERI64VPROC) load(userptr, "glGetBufferParameteri64v");
+    glad_glGetInteger64i_v = (PFNGLGETINTEGER64I_VPROC) load(userptr, "glGetInteger64i_v");
+    glad_glGetInteger64v = (PFNGLGETINTEGER64VPROC) load(userptr, "glGetInteger64v");
+    glad_glGetMultisamplefv = (PFNGLGETMULTISAMPLEFVPROC) load(userptr, "glGetMultisamplefv");
+    glad_glGetSynciv = (PFNGLGETSYNCIVPROC) load(userptr, "glGetSynciv");
+    glad_glIsSync = (PFNGLISSYNCPROC) load(userptr, "glIsSync");
+    glad_glMultiDrawElementsBaseVertex = (PFNGLMULTIDRAWELEMENTSBASEVERTEXPROC) load(userptr, "glMultiDrawElementsBaseVertex");
+    glad_glProvokingVertex = (PFNGLPROVOKINGVERTEXPROC) load(userptr, "glProvokingVertex");
+    glad_glSampleMaski = (PFNGLSAMPLEMASKIPROC) load(userptr, "glSampleMaski");
+    glad_glTexImage2DMultisample = (PFNGLTEXIMAGE2DMULTISAMPLEPROC) load(userptr, "glTexImage2DMultisample");
+    glad_glTexImage3DMultisample = (PFNGLTEXIMAGE3DMULTISAMPLEPROC) load(userptr, "glTexImage3DMultisample");
+    glad_glWaitSync = (PFNGLWAITSYNCPROC) load(userptr, "glWaitSync");
+}
+static void glad_gl_load_GL_VERSION_3_3( GLADuserptrloadfunc load, void* userptr) {
+    if(!GLAD_GL_VERSION_3_3) return;
+    glad_glBindFragDataLocationIndexed = (PFNGLBINDFRAGDATALOCATIONINDEXEDPROC) load(userptr, "glBindFragDataLocationIndexed");
+    glad_glBindSampler = (PFNGLBINDSAMPLERPROC) load(userptr, "glBindSampler");
+    glad_glDeleteSamplers = (PFNGLDELETESAMPLERSPROC) load(userptr, "glDeleteSamplers");
+    glad_glGenSamplers = (PFNGLGENSAMPLERSPROC) load(userptr, "glGenSamplers");
+    glad_glGetFragDataIndex = (PFNGLGETFRAGDATAINDEXPROC) load(userptr, "glGetFragDataIndex");
+    glad_glGetQueryObjecti64v = (PFNGLGETQUERYOBJECTI64VPROC) load(userptr, "glGetQueryObjecti64v");
+    glad_glGetQueryObjectui64v = (PFNGLGETQUERYOBJECTUI64VPROC) load(userptr, "glGetQueryObjectui64v");
+    glad_glGetSamplerParameterIiv = (PFNGLGETSAMPLERPARAMETERIIVPROC) load(userptr, "glGetSamplerParameterIiv");
+    glad_glGetSamplerParameterIuiv = (PFNGLGETSAMPLERPARAMETERIUIVPROC) load(userptr, "glGetSamplerParameterIuiv");
+    glad_glGetSamplerParameterfv = (PFNGLGETSAMPLERPARAMETERFVPROC) load(userptr, "glGetSamplerParameterfv");
+    glad_glGetSamplerParameteriv = (PFNGLGETSAMPLERPARAMETERIVPROC) load(userptr, "glGetSamplerParameteriv");
+    glad_glIsSampler = (PFNGLISSAMPLERPROC) load(userptr, "glIsSampler");
+    glad_glQueryCounter = (PFNGLQUERYCOUNTERPROC) load(userptr, "glQueryCounter");
+    glad_glSamplerParameterIiv = (PFNGLSAMPLERPARAMETERIIVPROC) load(userptr, "glSamplerParameterIiv");
+    glad_glSamplerParameterIuiv = (PFNGLSAMPLERPARAMETERIUIVPROC) load(userptr, "glSamplerParameterIuiv");
+    glad_glSamplerParameterf = (PFNGLSAMPLERPARAMETERFPROC) load(userptr, "glSamplerParameterf");
+    glad_glSamplerParameterfv = (PFNGLSAMPLERPARAMETERFVPROC) load(userptr, "glSamplerParameterfv");
+    glad_glSamplerParameteri = (PFNGLSAMPLERPARAMETERIPROC) load(userptr, "glSamplerParameteri");
+    glad_glSamplerParameteriv = (PFNGLSAMPLERPARAMETERIVPROC) load(userptr, "glSamplerParameteriv");
+    glad_glVertexAttribDivisor = (PFNGLVERTEXATTRIBDIVISORPROC) load(userptr, "glVertexAttribDivisor");
+    glad_glVertexAttribP1ui = (PFNGLVERTEXATTRIBP1UIPROC) load(userptr, "glVertexAttribP1ui");
+    glad_glVertexAttribP1uiv = (PFNGLVERTEXATTRIBP1UIVPROC) load(userptr, "glVertexAttribP1uiv");
+    glad_glVertexAttribP2ui = (PFNGLVERTEXATTRIBP2UIPROC) load(userptr, "glVertexAttribP2ui");
+    glad_glVertexAttribP2uiv = (PFNGLVERTEXATTRIBP2UIVPROC) load(userptr, "glVertexAttribP2uiv");
+    glad_glVertexAttribP3ui = (PFNGLVERTEXATTRIBP3UIPROC) load(userptr, "glVertexAttribP3ui");
+    glad_glVertexAttribP3uiv = (PFNGLVERTEXATTRIBP3UIVPROC) load(userptr, "glVertexAttribP3uiv");
+    glad_glVertexAttribP4ui = (PFNGLVERTEXATTRIBP4UIPROC) load(userptr, "glVertexAttribP4ui");
+    glad_glVertexAttribP4uiv = (PFNGLVERTEXATTRIBP4UIVPROC) load(userptr, "glVertexAttribP4uiv");
+}
+
+
+
+#if defined(GL_ES_VERSION_3_0) || defined(GL_VERSION_3_0)
+#define GLAD_GL_IS_SOME_NEW_VERSION 1
+#else
+#define GLAD_GL_IS_SOME_NEW_VERSION 0
+#endif
+
+static int glad_gl_get_extensions( int version, const char **out_exts, unsigned int *out_num_exts_i, char ***out_exts_i) {
+#if GLAD_GL_IS_SOME_NEW_VERSION
+    if(GLAD_VERSION_MAJOR(version) < 3) {
+#else
+    (void) version;
+    (void) out_num_exts_i;
+    (void) out_exts_i;
+#endif
+        if (glad_glGetString == NULL) {
+            return 0;
+        }
+        *out_exts = (const char *)glad_glGetString(GL_EXTENSIONS);
+#if GLAD_GL_IS_SOME_NEW_VERSION
+    } else {
+        unsigned int index = 0;
+        unsigned int num_exts_i = 0;
+        char **exts_i = NULL;
+        if (glad_glGetStringi == NULL || glad_glGetIntegerv == NULL) {
+            return 0;
+        }
+        glad_glGetIntegerv(GL_NUM_EXTENSIONS, (int*) &num_exts_i);
+        if (num_exts_i > 0) {
+            exts_i = (char **) malloc(num_exts_i * (sizeof *exts_i));
+        }
+        if (exts_i == NULL) {
+            return 0;
+        }
+        for(index = 0; index < num_exts_i; index++) {
+            const char *gl_str_tmp = (const char*) glad_glGetStringi(GL_EXTENSIONS, index);
+            size_t len = strlen(gl_str_tmp) + 1;
+
+            char *local_str = (char*) malloc(len * sizeof(char));
+            if(local_str != NULL) {
+                memcpy(local_str, gl_str_tmp, len * sizeof(char));
+            }
+
+            exts_i[index] = local_str;
+        }
+
+        *out_num_exts_i = num_exts_i;
+        *out_exts_i = exts_i;
+    }
+#endif
+    return 1;
+}
+static void glad_gl_free_extensions(char **exts_i, unsigned int num_exts_i) {
+    if (exts_i != NULL) {
+        unsigned int index;
+        for(index = 0; index < num_exts_i; index++) {
+            free((void *) (exts_i[index]));
+        }
+        free((void *)exts_i);
+        exts_i = NULL;
+    }
+}
+static int glad_gl_has_extension(int version, const char *exts, unsigned int num_exts_i, char **exts_i, const char *ext) {
+    if(GLAD_VERSION_MAJOR(version) < 3 || !GLAD_GL_IS_SOME_NEW_VERSION) {
+        const char *extensions;
+        const char *loc;
+        const char *terminator;
+        extensions = exts;
+        if(extensions == NULL || ext == NULL) {
+            return 0;
+        }
+        while(1) {
+            loc = strstr(extensions, ext);
+            if(loc == NULL) {
+                return 0;
+            }
+            terminator = loc + strlen(ext);
+            if((loc == extensions || *(loc - 1) == ' ') &&
+                (*terminator == ' ' || *terminator == '\0')) {
+                return 1;
+            }
+            extensions = terminator;
+        }
+    } else {
+        unsigned int index;
+        for(index = 0; index < num_exts_i; index++) {
+            const char *e = exts_i[index];
+            if(strcmp(e, ext) == 0) {
+                return 1;
+            }
+        }
+    }
+    return 0;
+}
+
+static GLADapiproc glad_gl_get_proc_from_userptr(void *userptr, const char* name) {
+    return (GLAD_GNUC_EXTENSION (GLADapiproc (*)(const char *name)) userptr)(name);
+}
+
+static int glad_gl_find_extensions_gl( int version) {
+    const char *exts = NULL;
+    unsigned int num_exts_i = 0;
+    char **exts_i = NULL;
+    if (!glad_gl_get_extensions(version, &exts, &num_exts_i, &exts_i)) return 0;
+
+    (void) glad_gl_has_extension;
+
+    glad_gl_free_extensions(exts_i, num_exts_i);
+
+    return 1;
+}
+
+static int glad_gl_find_core_gl(void) {
+    int i;
+    const char* version;
+    const char* prefixes[] = {
+        "OpenGL ES-CM ",
+        "OpenGL ES-CL ",
+        "OpenGL ES ",
+        "OpenGL SC ",
+        NULL
+    };
+    int major = 0;
+    int minor = 0;
+    version = (const char*) glad_glGetString(GL_VERSION);
+    if (!version) return 0;
+    for (i = 0;  prefixes[i];  i++) {
+        const size_t length = strlen(prefixes[i]);
+        if (strncmp(version, prefixes[i], length) == 0) {
+            version += length;
+            break;
+        }
+    }
+
+    GLAD_IMPL_UTIL_SSCANF(version, "%d.%d", &major, &minor);
+
+    GLAD_GL_VERSION_1_0 = (major == 1 && minor >= 0) || major > 1;
+    GLAD_GL_VERSION_1_1 = (major == 1 && minor >= 1) || major > 1;
+    GLAD_GL_VERSION_1_2 = (major == 1 && minor >= 2) || major > 1;
+    GLAD_GL_VERSION_1_3 = (major == 1 && minor >= 3) || major > 1;
+    GLAD_GL_VERSION_1_4 = (major == 1 && minor >= 4) || major > 1;
+    GLAD_GL_VERSION_1_5 = (major == 1 && minor >= 5) || major > 1;
+    GLAD_GL_VERSION_2_0 = (major == 2 && minor >= 0) || major > 2;
+    GLAD_GL_VERSION_2_1 = (major == 2 && minor >= 1) || major > 2;
+    GLAD_GL_VERSION_3_0 = (major == 3 && minor >= 0) || major > 3;
+    GLAD_GL_VERSION_3_1 = (major == 3 && minor >= 1) || major > 3;
+    GLAD_GL_VERSION_3_2 = (major == 3 && minor >= 2) || major > 3;
+    GLAD_GL_VERSION_3_3 = (major == 3 && minor >= 3) || major > 3;
+
+    return GLAD_MAKE_VERSION(major, minor);
+}
+
+int gladLoadGLUserPtr( GLADuserptrloadfunc load, void *userptr) {
+    int version;
+
+    glad_glGetString = (PFNGLGETSTRINGPROC) load(userptr, "glGetString");
+    if(glad_glGetString == NULL) return 0;
+    if(glad_glGetString(GL_VERSION) == NULL) return 0;
+    version = glad_gl_find_core_gl();
+
+    glad_gl_load_GL_VERSION_1_0(load, userptr);
+    glad_gl_load_GL_VERSION_1_1(load, userptr);
+    glad_gl_load_GL_VERSION_1_2(load, userptr);
+    glad_gl_load_GL_VERSION_1_3(load, userptr);
+    glad_gl_load_GL_VERSION_1_4(load, userptr);
+    glad_gl_load_GL_VERSION_1_5(load, userptr);
+    glad_gl_load_GL_VERSION_2_0(load, userptr);
+    glad_gl_load_GL_VERSION_2_1(load, userptr);
+    glad_gl_load_GL_VERSION_3_0(load, userptr);
+    glad_gl_load_GL_VERSION_3_1(load, userptr);
+    glad_gl_load_GL_VERSION_3_2(load, userptr);
+    glad_gl_load_GL_VERSION_3_3(load, userptr);
+
+    if (!glad_gl_find_extensions_gl(version)) return 0;
+
+
+
+    return version;
+}
+
+
+int gladLoadGL( GLADloadfunc load) {
+    return gladLoadGLUserPtr( glad_gl_get_proc_from_userptr, GLAD_GNUC_EXTENSION (void*) load);
+}
+
+
+
+ 
+
+#ifdef GLAD_GL
+
+#ifndef GLAD_LOADER_LIBRARY_C_
+#define GLAD_LOADER_LIBRARY_C_
+
+#include <stddef.h>
+#include <stdlib.h>
+
+#if GLAD_PLATFORM_WIN32
+#include <windows.h>
+#else
+#include <dlfcn.h>
+#endif
+
+
+static void* glad_get_dlopen_handle(const char *lib_names[], int length) {
+    void *handle = NULL;
+    int i;
+
+    for (i = 0; i < length; ++i) {
+#if GLAD_PLATFORM_WIN32
+  #if GLAD_PLATFORM_UWP
+        size_t buffer_size = (strlen(lib_names[i]) + 1) * sizeof(WCHAR);
+        LPWSTR buffer = (LPWSTR) malloc(buffer_size);
+        if (buffer != NULL) {
+            int ret = MultiByteToWideChar(CP_ACP, 0, lib_names[i], -1, buffer, buffer_size);
+            if (ret != 0) {
+                handle = (void*) LoadPackagedLibrary(buffer, 0);
+            }
+            free((void*) buffer);
+        }
+  #else
+        handle = (void*) LoadLibraryA(lib_names[i]);
+  #endif
+#else
+        handle = dlopen(lib_names[i], RTLD_LAZY | RTLD_LOCAL);
+#endif
+        if (handle != NULL) {
+            return handle;
+        }
+    }
+
+    return NULL;
+}
+
+static void glad_close_dlopen_handle(void* handle) {
+    if (handle != NULL) {
+#if GLAD_PLATFORM_WIN32
+        FreeLibrary((HMODULE) handle);
+#else
+        dlclose(handle);
+#endif
+    }
+}
+
+static GLADapiproc glad_dlsym_handle(void* handle, const char *name) {
+    if (handle == NULL) {
+        return NULL;
+    }
+
+#if GLAD_PLATFORM_WIN32
+    return (GLADapiproc) GetProcAddress((HMODULE) handle, name);
+#else
+    return GLAD_GNUC_EXTENSION (GLADapiproc) dlsym(handle, name);
+#endif
+}
+
+#endif /* GLAD_LOADER_LIBRARY_C_ */
+
+typedef void* (GLAD_API_PTR *GLADglprocaddrfunc)(const char*);
+struct _glad_gl_userptr {
+    void *handle;
+    GLADglprocaddrfunc gl_get_proc_address_ptr;
+};
+
+static GLADapiproc glad_gl_get_proc(void *vuserptr, const char *name) {
+    struct _glad_gl_userptr userptr = *(struct _glad_gl_userptr*) vuserptr;
+    GLADapiproc result = NULL;
+
+    if(userptr.gl_get_proc_address_ptr != NULL) {
+        result = GLAD_GNUC_EXTENSION (GLADapiproc) userptr.gl_get_proc_address_ptr(name);
+    }
+    if(result == NULL) {
+        result = glad_dlsym_handle(userptr.handle, name);
+    }
+
+    return result;
+}
+
+static void* _gl_handle = NULL;
+
+static void* glad_gl_dlopen_handle(void) {
+#if GLAD_PLATFORM_APPLE
+    static const char *NAMES[] = {
+        "../Frameworks/OpenGL.framework/OpenGL",
+        "/Library/Frameworks/OpenGL.framework/OpenGL",
+        "/System/Library/Frameworks/OpenGL.framework/OpenGL",
+        "/System/Library/Frameworks/OpenGL.framework/Versions/Current/OpenGL"
+    };
+#elif GLAD_PLATFORM_WIN32
+    static const char *NAMES[] = {"opengl32.dll"};
+#else
+    static const char *NAMES[] = {
+  #if defined(__CYGWIN__)
+        "libGL-1.so",
+  #endif
+        "libGL.so.1",
+        "libGL.so"
+    };
+#endif
+
+    if (_gl_handle == NULL) {
+        _gl_handle = glad_get_dlopen_handle(NAMES, sizeof(NAMES) / sizeof(NAMES[0]));
+    }
+
+    return _gl_handle;
+}
+
+static struct _glad_gl_userptr glad_gl_build_userptr(void *handle) {
+    struct _glad_gl_userptr userptr;
+
+    userptr.handle = handle;
+#if GLAD_PLATFORM_APPLE || defined(__HAIKU__)
+    userptr.gl_get_proc_address_ptr = NULL;
+#elif GLAD_PLATFORM_WIN32
+    userptr.gl_get_proc_address_ptr =
+        (GLADglprocaddrfunc) glad_dlsym_handle(handle, "wglGetProcAddress");
+#else
+    userptr.gl_get_proc_address_ptr =
+        (GLADglprocaddrfunc) glad_dlsym_handle(handle, "glXGetProcAddressARB");
+#endif
+
+    return userptr;
+}
+
+int gladLoaderLoadGL(void) {
+    int version = 0;
+    void *handle;
+    int did_load = 0;
+    struct _glad_gl_userptr userptr;
+
+    did_load = _gl_handle == NULL;
+    handle = glad_gl_dlopen_handle();
+    if (handle) {
+        userptr = glad_gl_build_userptr(handle);
+
+        version = gladLoadGLUserPtr(glad_gl_get_proc, &userptr);
+
+        if (did_load) {
+            gladLoaderUnloadGL();
+        }
+    }
+
+    return version;
+}
+
+
+
+void gladLoaderUnloadGL(void) {
+    if (_gl_handle != NULL) {
+        glad_close_dlopen_handle(_gl_handle);
+        _gl_handle = NULL;
+    }
+}
+
+#endif /* GLAD_GL */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* GLAD_GL_IMPLEMENTATION */
+

+ 18 - 18
Samples/shell/include/macosx/InputMacOSX.h → Backends/RmlUi_Include_Windows.h

@@ -15,7 +15,7 @@
  *
  * The above copyright notice and this permission notice shall be included in
  * all copies or substantial portions of the Software.
- * 
+ *
  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
@@ -26,26 +26,26 @@
  *
  */
 
-#ifndef RMLUI_SHELL_MACOSX_INPUTMACOSX_H
-#define RMLUI_SHELL_MACOSX_INPUTMACOSX_H
+#ifndef RMLUI_BACKENDS_INCLUDE_WINDOWS_H
+#define RMLUI_BACKENDS_INCLUDE_WINDOWS_H
 
-#include "Input.h"
-#include <Carbon/Carbon.h>
+#ifndef RMLUI_DISABLE_INCLUDE_WINDOWS
 
-/**
-	Input Wrapper Code
-	Feel free to take this class and integrate it with your project.
-	@author Lloyd Weehuizen
- */
+	#if !defined _WIN32_WINNT || _WIN32_WINNT < 0x0601
+		#undef _WIN32_WINNT
+		// Target Windows 7
+		#define _WIN32_WINNT 0x0601
+	#endif
 
-class InputMacOSX : public Input
-{
-public:
-	static bool Initialise();
-	static void Shutdown();
+	#define UNICODE
+	#define _UNICODE
+	#define WIN32_LEAN_AND_MEAN
+	#ifndef NOMINMAX
+		#define NOMINMAX
+	#endif
 
-	/// Process the Carbon event.
-	static OSStatus EventHandler(EventHandlerCallRef next_handler, EventRef event, void* p);
-};
+	#include <windows.h>
+
+#endif
 
 #endif

+ 18 - 12
Samples/shell/include/x11/X11MacroZapper.h → Backends/RmlUi_Include_Xlib.h

@@ -15,7 +15,7 @@
  *
  * The above copyright notice and this permission notice shall be included in
  * all copies or substantial portions of the Software.
- * 
+ *
  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
@@ -26,18 +26,24 @@
  *
  */
 
-#ifndef RMLUI_SHELL_X11_X11MACROZAPPER_H
-#define RMLUI_SHELL_X11_X11MACROZAPPER_H
+#ifndef RMLUI_BACKENDS_INCLUDE_XLIB_H
+#define RMLUI_BACKENDS_INCLUDE_XLIB_H
+
+#ifndef RMLUI_DISABLE_INCLUDE_XLIB
+
+	#include <X11/Xlib.h>
+
+	// The None and Always defines from X.h conflicts with RmlUi code base,
+	// use their underlying constants where necessary.
+	#ifdef None
+		// Value 0L
+		#undef None
+	#endif
+	#ifdef Always
+		// Value 2
+		#undef Always
+	#endif
 
-// The None and Always defines from X.h conflicts with RmlUi code base,
-// use their underlying constants where necessary.
-#ifdef None
-	// Value 0L
-	#undef None
-#endif
-#ifdef Always
-	// Value 2
-	#undef Always
 #endif
 
 #endif

+ 323 - 0
Backends/RmlUi_Platform_GLFW.cpp

@@ -0,0 +1,323 @@
+/*
+ * This source file is part of RmlUi, the HTML/CSS Interface Middleware
+ *
+ * For the latest information, see http://github.com/mikke89/RmlUi
+ *
+ * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd
+ * Copyright (c) 2019 The RmlUi Team, and contributors
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ */
+
+#include "RmlUi_Platform_GLFW.h"
+#include <RmlUi/Core/Context.h>
+#include <RmlUi/Core/Input.h>
+#include <RmlUi/Core/Log.h>
+#include <RmlUi/Core/SystemInterface.h>
+#include <GLFW/glfw3.h>
+
+SystemInterface_GLFW::SystemInterface_GLFW()
+{
+	cursor_pointer = glfwCreateStandardCursor(GLFW_HAND_CURSOR);
+	cursor_cross = glfwCreateStandardCursor(GLFW_CROSSHAIR_CURSOR);
+	cursor_text = glfwCreateStandardCursor(GLFW_IBEAM_CURSOR);
+}
+
+SystemInterface_GLFW::~SystemInterface_GLFW()
+{
+	glfwDestroyCursor(cursor_pointer);
+	glfwDestroyCursor(cursor_cross);
+	glfwDestroyCursor(cursor_text);
+}
+
+void SystemInterface_GLFW::SetWindow(GLFWwindow* in_window)
+{
+	window = in_window;
+}
+
+double SystemInterface_GLFW::GetElapsedTime()
+{
+	return glfwGetTime();
+}
+
+void SystemInterface_GLFW::SetMouseCursor(const Rml::String& cursor_name)
+{
+	GLFWcursor* cursor = nullptr;
+
+	if (cursor_name.empty() || cursor_name == "arrow")
+		cursor = nullptr;
+	else if (cursor_name == "move")
+		cursor = cursor_pointer;
+	else if (cursor_name == "pointer")
+		cursor = cursor_pointer;
+	else if (cursor_name == "resize")
+		cursor = cursor_pointer;
+	else if (cursor_name == "cross")
+		cursor = cursor_cross;
+	else if (cursor_name == "text")
+		cursor = cursor_text;
+	else if (cursor_name == "unavailable")
+		cursor = nullptr;
+
+	if (window)
+		glfwSetCursor(window, cursor);
+}
+
+void SystemInterface_GLFW::SetClipboardText(const Rml::String& text_utf8)
+{
+	if (window)
+		glfwSetClipboardString(window, text_utf8.c_str());
+}
+
+void SystemInterface_GLFW::GetClipboardText(Rml::String& text)
+{
+	if (window)
+		text = Rml::String(glfwGetClipboardString(window));
+}
+
+bool RmlGLFW::ProcessKeyCallback(Rml::Context* context, int key, int action, int mods)
+{
+	if (!context)
+		return true;
+
+	bool result = true;
+
+	switch (action)
+	{
+	case GLFW_PRESS:
+	case GLFW_REPEAT:
+		result = context->ProcessKeyDown(RmlGLFW::ConvertKey(key), RmlGLFW::ConvertKeyModifiers(mods));
+		if (key == GLFW_KEY_ENTER || key == GLFW_KEY_KP_ENTER)
+			result &= context->ProcessTextInput('\n');
+		break;
+	case GLFW_RELEASE:
+		result = context->ProcessKeyUp(RmlGLFW::ConvertKey(key), RmlGLFW::ConvertKeyModifiers(mods));
+		break;
+	}
+
+	return result;
+}
+bool RmlGLFW::ProcessCharCallback(Rml::Context* context, unsigned int codepoint)
+{
+	if (!context)
+		return true;
+
+	bool result = context->ProcessTextInput((Rml::Character)codepoint);
+	return result;
+}
+
+bool RmlGLFW::ProcessCursorPosCallback(Rml::Context* context, double xpos, double ypos, int mods)
+{
+	if (!context)
+		return true;
+
+	bool result = context->ProcessMouseMove(int(xpos), int(ypos), RmlGLFW::ConvertKeyModifiers(mods));
+	return result;
+}
+
+bool RmlGLFW::ProcessMouseButtonCallback(Rml::Context* context, int button, int action, int mods)
+{
+	if (!context)
+		return true;
+
+	bool result = true;
+
+	switch (action)
+	{
+	case GLFW_PRESS:
+		result = context->ProcessMouseButtonDown(button, RmlGLFW::ConvertKeyModifiers(mods));
+		break;
+	case GLFW_RELEASE:
+		result = context->ProcessMouseButtonUp(button, RmlGLFW::ConvertKeyModifiers(mods));
+		break;
+	}
+	return result;
+}
+
+bool RmlGLFW::ProcessScrollCallback(Rml::Context* context, double yoffset, int mods)
+{
+	if (!context)
+		return true;
+
+	bool result = context->ProcessMouseWheel(-float(yoffset), RmlGLFW::ConvertKeyModifiers(mods));
+	return result;
+}
+
+void RmlGLFW::ProcessFramebufferSizeCallback(Rml::Context* context, int width, int height)
+{
+	if (context)
+		context->SetDimensions(Rml::Vector2i(width, height));
+}
+
+void RmlGLFW::ProcessContentScaleCallback(Rml::Context* context, float xscale)
+{
+	if (context)
+		context->SetDensityIndependentPixelRatio(xscale);
+}
+
+int RmlGLFW::ConvertKeyModifiers(int glfw_mods)
+{
+	int key_modifier_state = 0;
+
+	if (GLFW_MOD_SHIFT & glfw_mods)
+		key_modifier_state |= Rml::Input::KM_SHIFT;
+
+	if (GLFW_MOD_CONTROL & glfw_mods)
+		key_modifier_state |= Rml::Input::KM_CTRL;
+
+	if (GLFW_MOD_ALT & glfw_mods)
+		key_modifier_state |= Rml::Input::KM_ALT;
+
+	if (GLFW_MOD_CAPS_LOCK & glfw_mods)
+		key_modifier_state |= Rml::Input::KM_SCROLLLOCK;
+
+	if (GLFW_MOD_NUM_LOCK & glfw_mods)
+		key_modifier_state |= Rml::Input::KM_NUMLOCK;
+
+	return key_modifier_state;
+}
+
+Rml::Input::KeyIdentifier RmlGLFW::ConvertKey(int glfw_key)
+{
+	// clang-format off
+	switch (glfw_key)
+	{
+	case GLFW_KEY_A:             return Rml::Input::KI_A;
+	case GLFW_KEY_B:             return Rml::Input::KI_B;
+	case GLFW_KEY_C:             return Rml::Input::KI_C;
+	case GLFW_KEY_D:             return Rml::Input::KI_D;
+	case GLFW_KEY_E:             return Rml::Input::KI_E;
+	case GLFW_KEY_F:             return Rml::Input::KI_F;
+	case GLFW_KEY_G:             return Rml::Input::KI_G;
+	case GLFW_KEY_H:             return Rml::Input::KI_H;
+	case GLFW_KEY_I:             return Rml::Input::KI_I;
+	case GLFW_KEY_J:             return Rml::Input::KI_J;
+	case GLFW_KEY_K:             return Rml::Input::KI_K;
+	case GLFW_KEY_L:             return Rml::Input::KI_L;
+	case GLFW_KEY_M:             return Rml::Input::KI_M;
+	case GLFW_KEY_N:             return Rml::Input::KI_N;
+	case GLFW_KEY_O:             return Rml::Input::KI_O;
+	case GLFW_KEY_P:             return Rml::Input::KI_P;
+	case GLFW_KEY_Q:             return Rml::Input::KI_Q;
+	case GLFW_KEY_R:             return Rml::Input::KI_R;
+	case GLFW_KEY_S:             return Rml::Input::KI_S;
+	case GLFW_KEY_T:             return Rml::Input::KI_T;
+	case GLFW_KEY_U:             return Rml::Input::KI_U;
+	case GLFW_KEY_V:             return Rml::Input::KI_V;
+	case GLFW_KEY_W:             return Rml::Input::KI_W;
+	case GLFW_KEY_X:             return Rml::Input::KI_X;
+	case GLFW_KEY_Y:             return Rml::Input::KI_Y;
+	case GLFW_KEY_Z:             return Rml::Input::KI_Z;
+
+	case GLFW_KEY_0:             return Rml::Input::KI_0;
+	case GLFW_KEY_1:             return Rml::Input::KI_1;
+	case GLFW_KEY_2:             return Rml::Input::KI_2;
+	case GLFW_KEY_3:             return Rml::Input::KI_3;
+	case GLFW_KEY_4:             return Rml::Input::KI_4;
+	case GLFW_KEY_5:             return Rml::Input::KI_5;
+	case GLFW_KEY_6:             return Rml::Input::KI_6;
+	case GLFW_KEY_7:             return Rml::Input::KI_7;
+	case GLFW_KEY_8:             return Rml::Input::KI_8;
+	case GLFW_KEY_9:             return Rml::Input::KI_9;
+
+	case GLFW_KEY_BACKSPACE:     return Rml::Input::KI_BACK;
+	case GLFW_KEY_TAB:           return Rml::Input::KI_TAB;
+
+	case GLFW_KEY_ENTER:         return Rml::Input::KI_RETURN;
+
+	case GLFW_KEY_PAUSE:         return Rml::Input::KI_PAUSE;
+	case GLFW_KEY_CAPS_LOCK:     return Rml::Input::KI_CAPITAL;
+
+	case GLFW_KEY_ESCAPE:        return Rml::Input::KI_ESCAPE;
+
+	case GLFW_KEY_SPACE:         return Rml::Input::KI_SPACE;
+	case GLFW_KEY_PAGE_UP:       return Rml::Input::KI_PRIOR;
+	case GLFW_KEY_PAGE_DOWN:     return Rml::Input::KI_NEXT;
+	case GLFW_KEY_END:           return Rml::Input::KI_END;
+	case GLFW_KEY_HOME:          return Rml::Input::KI_HOME;
+	case GLFW_KEY_LEFT:          return Rml::Input::KI_LEFT;
+	case GLFW_KEY_UP:            return Rml::Input::KI_UP;
+	case GLFW_KEY_RIGHT:         return Rml::Input::KI_RIGHT;
+	case GLFW_KEY_DOWN:          return Rml::Input::KI_DOWN;
+	case GLFW_KEY_PRINT_SCREEN:  return Rml::Input::KI_SNAPSHOT;
+	case GLFW_KEY_INSERT:        return Rml::Input::KI_INSERT;
+	case GLFW_KEY_DELETE:        return Rml::Input::KI_DELETE;
+
+	case GLFW_KEY_LEFT_SUPER:    return Rml::Input::KI_LWIN;
+	case GLFW_KEY_RIGHT_SUPER:   return Rml::Input::KI_RWIN;
+
+	case GLFW_KEY_KP_0:          return Rml::Input::KI_NUMPAD0;
+	case GLFW_KEY_KP_1:          return Rml::Input::KI_NUMPAD1;
+	case GLFW_KEY_KP_2:          return Rml::Input::KI_NUMPAD2;
+	case GLFW_KEY_KP_3:          return Rml::Input::KI_NUMPAD3;
+	case GLFW_KEY_KP_4:          return Rml::Input::KI_NUMPAD4;
+	case GLFW_KEY_KP_5:          return Rml::Input::KI_NUMPAD5;
+	case GLFW_KEY_KP_6:          return Rml::Input::KI_NUMPAD6;
+	case GLFW_KEY_KP_7:          return Rml::Input::KI_NUMPAD7;
+	case GLFW_KEY_KP_8:          return Rml::Input::KI_NUMPAD8;
+	case GLFW_KEY_KP_9:          return Rml::Input::KI_NUMPAD9;
+	case GLFW_KEY_KP_ENTER:      return Rml::Input::KI_NUMPADENTER;
+	case GLFW_KEY_KP_MULTIPLY:   return Rml::Input::KI_MULTIPLY;
+	case GLFW_KEY_KP_ADD:        return Rml::Input::KI_ADD;
+	case GLFW_KEY_KP_SUBTRACT:   return Rml::Input::KI_SUBTRACT;
+	case GLFW_KEY_KP_DECIMAL:    return Rml::Input::KI_DECIMAL;
+	case GLFW_KEY_KP_DIVIDE:     return Rml::Input::KI_DIVIDE;
+
+	case GLFW_KEY_F1:            return Rml::Input::KI_F1;
+	case GLFW_KEY_F2:            return Rml::Input::KI_F2;
+	case GLFW_KEY_F3:            return Rml::Input::KI_F3;
+	case GLFW_KEY_F4:            return Rml::Input::KI_F4;
+	case GLFW_KEY_F5:            return Rml::Input::KI_F5;
+	case GLFW_KEY_F6:            return Rml::Input::KI_F6;
+	case GLFW_KEY_F7:            return Rml::Input::KI_F7;
+	case GLFW_KEY_F8:            return Rml::Input::KI_F8;
+	case GLFW_KEY_F9:            return Rml::Input::KI_F9;
+	case GLFW_KEY_F10:           return Rml::Input::KI_F10;
+	case GLFW_KEY_F11:           return Rml::Input::KI_F11;
+	case GLFW_KEY_F12:           return Rml::Input::KI_F12;
+	case GLFW_KEY_F13:           return Rml::Input::KI_F13;
+	case GLFW_KEY_F14:           return Rml::Input::KI_F14;
+	case GLFW_KEY_F15:           return Rml::Input::KI_F15;
+	case GLFW_KEY_F16:           return Rml::Input::KI_F16;
+	case GLFW_KEY_F17:           return Rml::Input::KI_F17;
+	case GLFW_KEY_F18:           return Rml::Input::KI_F18;
+	case GLFW_KEY_F19:           return Rml::Input::KI_F19;
+	case GLFW_KEY_F20:           return Rml::Input::KI_F20;
+	case GLFW_KEY_F21:           return Rml::Input::KI_F21;
+	case GLFW_KEY_F22:           return Rml::Input::KI_F22;
+	case GLFW_KEY_F23:           return Rml::Input::KI_F23;
+	case GLFW_KEY_F24:           return Rml::Input::KI_F24;
+
+	case GLFW_KEY_NUM_LOCK:      return Rml::Input::KI_NUMLOCK;
+	case GLFW_KEY_SCROLL_LOCK:   return Rml::Input::KI_SCROLL;
+
+	case GLFW_KEY_LEFT_SHIFT:    return Rml::Input::KI_LSHIFT;
+	case GLFW_KEY_LEFT_CONTROL:  return Rml::Input::KI_LCONTROL;
+	case GLFW_KEY_RIGHT_SHIFT:   return Rml::Input::KI_RSHIFT;
+	case GLFW_KEY_RIGHT_CONTROL: return Rml::Input::KI_RCONTROL;
+	case GLFW_KEY_MENU:          return Rml::Input::KI_LMENU;
+
+	case GLFW_KEY_KP_EQUAL:      return Rml::Input::KI_OEM_NEC_EQUAL;
+	default: break;
+	}
+	// clang-format on
+
+	return Rml::Input::KI_UNKNOWN;
+}

+ 86 - 0
Backends/RmlUi_Platform_GLFW.h

@@ -0,0 +1,86 @@
+/*
+ * This source file is part of RmlUi, the HTML/CSS Interface Middleware
+ *
+ * For the latest information, see http://github.com/mikke89/RmlUi
+ *
+ * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd
+ * Copyright (c) 2019 The RmlUi Team, and contributors
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ */
+
+#ifndef RMLUI_BACKENDS_PLATFORM_GLFW_H
+#define RMLUI_BACKENDS_PLATFORM_GLFW_H
+
+#include <RmlUi/Core/Input.h>
+#include <RmlUi/Core/SystemInterface.h>
+#include <RmlUi/Core/Types.h>
+#include <GLFW/glfw3.h>
+
+class SystemInterface_GLFW : public Rml::SystemInterface {
+public:
+	SystemInterface_GLFW();
+	~SystemInterface_GLFW();
+
+	// Optionally, provide or change the window to be used for setting the mouse cursors and clipboard text.
+	void SetWindow(GLFWwindow* window);
+
+	// -- Inherited from Rml::SystemInterface  --
+
+	double GetElapsedTime() override;
+
+	void SetMouseCursor(const Rml::String& cursor_name) override;
+
+	void SetClipboardText(const Rml::String& text) override;
+	void GetClipboardText(Rml::String& text) override;
+
+private:
+	GLFWwindow* window = nullptr;
+
+	GLFWcursor* cursor_pointer = nullptr;
+	GLFWcursor* cursor_cross = nullptr;
+	GLFWcursor* cursor_text = nullptr;
+};
+
+/**
+    Optional helper functions for the GLFW plaform.
+ */
+namespace RmlGLFW {
+
+// The following optional functions are intended to be called from their respective GLFW callback functions. The functions expect arguments passed
+// directly from GLFW, in addition to the RmlUi context to apply the input or sizing event on. The input callbacks return true if the event is
+// propagating, i.e. was not handled by the context.
+bool ProcessKeyCallback(Rml::Context* context, int key, int action, int mods);
+bool ProcessCharCallback(Rml::Context* context, unsigned int codepoint);
+bool ProcessCursorPosCallback(Rml::Context* context, double xpos, double ypos, int mods);
+bool ProcessMouseButtonCallback(Rml::Context* context, int button, int action, int mods);
+bool ProcessScrollCallback(Rml::Context* context, double yoffset, int mods);
+void ProcessFramebufferSizeCallback(Rml::Context* context, int width, int height);
+void ProcessContentScaleCallback(Rml::Context* context, float xscale);
+
+// Converts the GLFW key to RmlUi key.
+Rml::Input::KeyIdentifier ConvertKey(int glfw_key);
+
+// Converts the GLFW key modifiers to RmlUi key modifiers.
+int ConvertKeyModifiers(int glfw_mods);
+
+} // namespace RmlGLFW
+
+#endif

+ 296 - 0
Backends/RmlUi_Platform_SDL.cpp

@@ -0,0 +1,296 @@
+/*
+ * This source file is part of RmlUi, the HTML/CSS Interface Middleware
+ *
+ * For the latest information, see http://github.com/mikke89/RmlUi
+ *
+ * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd
+ * Copyright (c) 2019 The RmlUi Team, and contributors
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ */
+
+#include "RmlUi_Platform_SDL.h"
+#include <RmlUi/Core/Context.h>
+#include <RmlUi/Core/Input.h>
+#include <RmlUi/Core/SystemInterface.h>
+#include <SDL.h>
+
+SystemInterface_SDL::SystemInterface_SDL()
+{
+	cursor_default = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_ARROW);
+	cursor_move = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_SIZEALL);
+	cursor_pointer = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_HAND);
+	cursor_resize = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_SIZENWSE);
+	cursor_cross = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_CROSSHAIR);
+	cursor_text = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_IBEAM);
+	cursor_unavailable = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_NO);
+}
+
+SystemInterface_SDL::~SystemInterface_SDL()
+{
+	SDL_FreeCursor(cursor_default);
+	SDL_FreeCursor(cursor_move);
+	SDL_FreeCursor(cursor_pointer);
+	SDL_FreeCursor(cursor_resize);
+	SDL_FreeCursor(cursor_cross);
+	SDL_FreeCursor(cursor_text);
+	SDL_FreeCursor(cursor_unavailable);
+}
+
+void SystemInterface_SDL::SetWindow(SDL_Window* in_window)
+{
+	window = in_window;
+}
+
+double SystemInterface_SDL::GetElapsedTime()
+{
+	return double(SDL_GetTicks()) / 1000.0;
+}
+
+void SystemInterface_SDL::SetMouseCursor(const Rml::String& cursor_name)
+{
+	SDL_Cursor* cursor = nullptr;
+
+	if (cursor_name.empty() || cursor_name == "arrow")
+		cursor = cursor_default;
+	else if (cursor_name == "move")
+		cursor = cursor_move;
+	else if (cursor_name == "pointer")
+		cursor = cursor_pointer;
+	else if (cursor_name == "resize")
+		cursor = cursor_resize;
+	else if (cursor_name == "cross")
+		cursor = cursor_cross;
+	else if (cursor_name == "text")
+		cursor = cursor_text;
+	else if (cursor_name == "unavailable")
+		cursor = cursor_unavailable;
+
+	if (cursor)
+		SDL_SetCursor(cursor);
+}
+
+void SystemInterface_SDL::SetClipboardText(const Rml::String& text_utf8)
+{
+	SDL_SetClipboardText(text_utf8.c_str());
+}
+
+void SystemInterface_SDL::GetClipboardText(Rml::String& text)
+{
+	char* raw_text = SDL_GetClipboardText();
+	text = Rml::String(raw_text);
+	SDL_free(raw_text);
+}
+
+bool RmlSDL::InputEventHandler(Rml::Context* context, SDL_Event& ev)
+{
+	bool result = true;
+
+	switch (ev.type)
+	{
+	case SDL_MOUSEMOTION:
+		result = context->ProcessMouseMove(ev.motion.x, ev.motion.y, GetKeyModifierState());
+		break;
+	case SDL_MOUSEBUTTONDOWN:
+		result = context->ProcessMouseButtonDown(ConvertMouseButton(ev.button.button), GetKeyModifierState());
+		SDL_CaptureMouse(SDL_TRUE);
+		break;
+	case SDL_MOUSEBUTTONUP:
+		SDL_CaptureMouse(SDL_FALSE);
+		result = context->ProcessMouseButtonUp(ConvertMouseButton(ev.button.button), GetKeyModifierState());
+		break;
+	case SDL_MOUSEWHEEL:
+		result = context->ProcessMouseWheel(float(-ev.wheel.y), GetKeyModifierState());
+		break;
+	case SDL_KEYDOWN:
+		result = context->ProcessKeyDown(ConvertKey(ev.key.keysym.sym), GetKeyModifierState());
+		if (ev.key.keysym.sym == SDLK_RETURN || ev.key.keysym.sym == SDLK_KP_ENTER)
+			result &= context->ProcessTextInput('\n');
+		break;
+	case SDL_KEYUP:
+		result = context->ProcessKeyUp(ConvertKey(ev.key.keysym.sym), GetKeyModifierState());
+		break;
+	case SDL_TEXTINPUT:
+		result = context->ProcessTextInput(Rml::String(&ev.text.text[0]));
+		break;
+	default:
+		break;
+	}
+
+	return result;
+}
+
+Rml::Input::KeyIdentifier RmlSDL::ConvertKey(int sdlkey)
+{
+	// clang-format off
+	switch (sdlkey)
+	{
+	case SDLK_UNKNOWN:      return Rml::Input::KI_UNKNOWN;
+	case SDLK_ESCAPE:       return Rml::Input::KI_ESCAPE;
+	case SDLK_SPACE:        return Rml::Input::KI_SPACE;
+	case SDLK_0:            return Rml::Input::KI_0;
+	case SDLK_1:            return Rml::Input::KI_1;
+	case SDLK_2:            return Rml::Input::KI_2;
+	case SDLK_3:            return Rml::Input::KI_3;
+	case SDLK_4:            return Rml::Input::KI_4;
+	case SDLK_5:            return Rml::Input::KI_5;
+	case SDLK_6:            return Rml::Input::KI_6;
+	case SDLK_7:            return Rml::Input::KI_7;
+	case SDLK_8:            return Rml::Input::KI_8;
+	case SDLK_9:            return Rml::Input::KI_9;
+	case SDLK_a:            return Rml::Input::KI_A;
+	case SDLK_b:            return Rml::Input::KI_B;
+	case SDLK_c:            return Rml::Input::KI_C;
+	case SDLK_d:            return Rml::Input::KI_D;
+	case SDLK_e:            return Rml::Input::KI_E;
+	case SDLK_f:            return Rml::Input::KI_F;
+	case SDLK_g:            return Rml::Input::KI_G;
+	case SDLK_h:            return Rml::Input::KI_H;
+	case SDLK_i:            return Rml::Input::KI_I;
+	case SDLK_j:            return Rml::Input::KI_J;
+	case SDLK_k:            return Rml::Input::KI_K;
+	case SDLK_l:            return Rml::Input::KI_L;
+	case SDLK_m:            return Rml::Input::KI_M;
+	case SDLK_n:            return Rml::Input::KI_N;
+	case SDLK_o:            return Rml::Input::KI_O;
+	case SDLK_p:            return Rml::Input::KI_P;
+	case SDLK_q:            return Rml::Input::KI_Q;
+	case SDLK_r:            return Rml::Input::KI_R;
+	case SDLK_s:            return Rml::Input::KI_S;
+	case SDLK_t:            return Rml::Input::KI_T;
+	case SDLK_u:            return Rml::Input::KI_U;
+	case SDLK_v:            return Rml::Input::KI_V;
+	case SDLK_w:            return Rml::Input::KI_W;
+	case SDLK_x:            return Rml::Input::KI_X;
+	case SDLK_y:            return Rml::Input::KI_Y;
+	case SDLK_z:            return Rml::Input::KI_Z;
+	case SDLK_SEMICOLON:    return Rml::Input::KI_OEM_1;
+	case SDLK_PLUS:         return Rml::Input::KI_OEM_PLUS;
+	case SDLK_COMMA:        return Rml::Input::KI_OEM_COMMA;
+	case SDLK_MINUS:        return Rml::Input::KI_OEM_MINUS;
+	case SDLK_PERIOD:       return Rml::Input::KI_OEM_PERIOD;
+	case SDLK_SLASH:        return Rml::Input::KI_OEM_2;
+	case SDLK_BACKQUOTE:    return Rml::Input::KI_OEM_3;
+	case SDLK_LEFTBRACKET:  return Rml::Input::KI_OEM_4;
+	case SDLK_BACKSLASH:    return Rml::Input::KI_OEM_5;
+	case SDLK_RIGHTBRACKET: return Rml::Input::KI_OEM_6;
+	case SDLK_QUOTEDBL:     return Rml::Input::KI_OEM_7;
+	case SDLK_KP_0:         return Rml::Input::KI_NUMPAD0;
+	case SDLK_KP_1:         return Rml::Input::KI_NUMPAD1;
+	case SDLK_KP_2:         return Rml::Input::KI_NUMPAD2;
+	case SDLK_KP_3:         return Rml::Input::KI_NUMPAD3;
+	case SDLK_KP_4:         return Rml::Input::KI_NUMPAD4;
+	case SDLK_KP_5:         return Rml::Input::KI_NUMPAD5;
+	case SDLK_KP_6:         return Rml::Input::KI_NUMPAD6;
+	case SDLK_KP_7:         return Rml::Input::KI_NUMPAD7;
+	case SDLK_KP_8:         return Rml::Input::KI_NUMPAD8;
+	case SDLK_KP_9:         return Rml::Input::KI_NUMPAD9;
+	case SDLK_KP_ENTER:     return Rml::Input::KI_NUMPADENTER;
+	case SDLK_KP_MULTIPLY:  return Rml::Input::KI_MULTIPLY;
+	case SDLK_KP_PLUS:      return Rml::Input::KI_ADD;
+	case SDLK_KP_MINUS:     return Rml::Input::KI_SUBTRACT;
+	case SDLK_KP_PERIOD:    return Rml::Input::KI_DECIMAL;
+	case SDLK_KP_DIVIDE:    return Rml::Input::KI_DIVIDE;
+	case SDLK_KP_EQUALS:    return Rml::Input::KI_OEM_NEC_EQUAL;
+	case SDLK_BACKSPACE:    return Rml::Input::KI_BACK;
+	case SDLK_TAB:          return Rml::Input::KI_TAB;
+	case SDLK_CLEAR:        return Rml::Input::KI_CLEAR;
+	case SDLK_RETURN:       return Rml::Input::KI_RETURN;
+	case SDLK_PAUSE:        return Rml::Input::KI_PAUSE;
+	case SDLK_CAPSLOCK:     return Rml::Input::KI_CAPITAL;
+	case SDLK_PAGEUP:       return Rml::Input::KI_PRIOR;
+	case SDLK_PAGEDOWN:     return Rml::Input::KI_NEXT;
+	case SDLK_END:          return Rml::Input::KI_END;
+	case SDLK_HOME:         return Rml::Input::KI_HOME;
+	case SDLK_LEFT:         return Rml::Input::KI_LEFT;
+	case SDLK_UP:           return Rml::Input::KI_UP;
+	case SDLK_RIGHT:        return Rml::Input::KI_RIGHT;
+	case SDLK_DOWN:         return Rml::Input::KI_DOWN;
+	case SDLK_INSERT:       return Rml::Input::KI_INSERT;
+	case SDLK_DELETE:       return Rml::Input::KI_DELETE;
+	case SDLK_HELP:         return Rml::Input::KI_HELP;
+	case SDLK_F1:           return Rml::Input::KI_F1;
+	case SDLK_F2:           return Rml::Input::KI_F2;
+	case SDLK_F3:           return Rml::Input::KI_F3;
+	case SDLK_F4:           return Rml::Input::KI_F4;
+	case SDLK_F5:           return Rml::Input::KI_F5;
+	case SDLK_F6:           return Rml::Input::KI_F6;
+	case SDLK_F7:           return Rml::Input::KI_F7;
+	case SDLK_F8:           return Rml::Input::KI_F8;
+	case SDLK_F9:           return Rml::Input::KI_F9;
+	case SDLK_F10:          return Rml::Input::KI_F10;
+	case SDLK_F11:          return Rml::Input::KI_F11;
+	case SDLK_F12:          return Rml::Input::KI_F12;
+	case SDLK_F13:          return Rml::Input::KI_F13;
+	case SDLK_F14:          return Rml::Input::KI_F14;
+	case SDLK_F15:          return Rml::Input::KI_F15;
+	case SDLK_NUMLOCKCLEAR: return Rml::Input::KI_NUMLOCK;
+	case SDLK_SCROLLLOCK:   return Rml::Input::KI_SCROLL;
+	case SDLK_LSHIFT:       return Rml::Input::KI_LSHIFT;
+	case SDLK_RSHIFT:       return Rml::Input::KI_RSHIFT;
+	case SDLK_LCTRL:        return Rml::Input::KI_LCONTROL;
+	case SDLK_RCTRL:        return Rml::Input::KI_RCONTROL;
+	case SDLK_LALT:         return Rml::Input::KI_LMENU;
+	case SDLK_RALT:         return Rml::Input::KI_RMENU;
+	case SDLK_LGUI:         return Rml::Input::KI_LMETA;
+	case SDLK_RGUI:         return Rml::Input::KI_RMETA;
+	/*
+	case SDLK_LSUPER:       return Rml::Input::KI_LWIN;
+	case SDLK_RSUPER:       return Rml::Input::KI_RWIN;
+	*/
+	default: break;
+	}
+	// clang-format on
+
+	return Rml::Input::KI_UNKNOWN;
+}
+
+int RmlSDL::ConvertMouseButton(int button)
+{
+	switch (button)
+	{
+	case SDL_BUTTON_LEFT:
+		return 0;
+	case SDL_BUTTON_RIGHT:
+		return 1;
+	case SDL_BUTTON_MIDDLE:
+		return 2;
+	default:
+		return 3;
+	}
+}
+
+int RmlSDL::GetKeyModifierState()
+{
+	SDL_Keymod sdlMods = SDL_GetModState();
+
+	int retval = 0;
+
+	if (sdlMods & KMOD_CTRL)
+		retval |= Rml::Input::KM_CTRL;
+
+	if (sdlMods & KMOD_SHIFT)
+		retval |= Rml::Input::KM_SHIFT;
+
+	if (sdlMods & KMOD_ALT)
+		retval |= Rml::Input::KM_ALT;
+
+	return retval;
+}

+ 43 - 19
Samples/shell/include/ShellSystemInterface.h → Backends/RmlUi_Platform_SDL.h

@@ -15,7 +15,7 @@
  *
  * The above copyright notice and this permission notice shall be included in
  * all copies or substantial portions of the Software.
- * 
+ *
  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
@@ -26,34 +26,58 @@
  *
  */
 
-#ifndef RMLUI_SHELL_SHELLSYSTEMINTERFACE_H
-#define RMLUI_SHELL_SHELLSYSTEMINTERFACE_H
+#ifndef RMLUI_BACKENDS_PLATFORM_SDL_H
+#define RMLUI_BACKENDS_PLATFORM_SDL_H
 
+#include <RmlUi/Core/Input.h>
 #include <RmlUi/Core/SystemInterface.h>
+#include <RmlUi/Core/Types.h>
+#include <SDL.h>
 
-/**
-	A custom system interface for RmlUi. This provides timing information.
-	@author Lloyd Weehuizen
- */
-
-class ShellSystemInterface : public Rml::SystemInterface
-{
+class SystemInterface_SDL : public Rml::SystemInterface {
 public:
-	/// Get the number of seconds elapsed since the start of the application
-	/// @returns Seconds elapsed
+	SystemInterface_SDL();
+	~SystemInterface_SDL();
+
+	// Optionally, provide or change the window to be used for setting the mouse cursors.
+	void SetWindow(SDL_Window* window);
+
+	// -- Inherited from Rml::SystemInterface  --
+
 	double GetElapsedTime() override;
 
-	/// Set mouse cursor.
-	/// @param[in] cursor_name Cursor name to activate.
 	void SetMouseCursor(const Rml::String& cursor_name) override;
 
-	/// Set clipboard text.
-	/// @param[in] text Text to apply to clipboard.
 	void SetClipboardText(const Rml::String& text) override;
-
-	/// Get clipboard text.
-	/// @param[out] text Retrieved text from clipboard.
 	void GetClipboardText(Rml::String& text) override;
+
+private:
+	SDL_Window* window = nullptr;
+
+	SDL_Cursor* cursor_default = nullptr;
+	SDL_Cursor* cursor_move = nullptr;
+	SDL_Cursor* cursor_pointer = nullptr;
+	SDL_Cursor* cursor_resize = nullptr;
+	SDL_Cursor* cursor_cross = nullptr;
+	SDL_Cursor* cursor_text = nullptr;
+	SDL_Cursor* cursor_unavailable = nullptr;
 };
 
+namespace RmlSDL {
+
+// Applies input on the context based on the given SDL event.
+// @return True if the event is still propagating, false if it was handled by the context.
+bool InputEventHandler(Rml::Context* context, SDL_Event& ev);
+
+// Converts the SDL key to RmlUi key.
+Rml::Input::KeyIdentifier ConvertKey(int sdl_key);
+
+// Converts the SDL mouse button to RmlUi mouse button.
+int ConvertMouseButton(int sdl_mouse_button);
+
+// Returns the active RmlUi key modifier state.
+int GetKeyModifierState();
+
+} // namespace RmlSDL
+
 #endif

+ 244 - 0
Backends/RmlUi_Platform_SFML.cpp

@@ -0,0 +1,244 @@
+/*
+ * This source file is part of RmlUi, the HTML/CSS Interface Middleware
+ *
+ * For the latest information, see http://github.com/mikke89/RmlUi
+ *
+ * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd
+ * Copyright (c) 2019 The RmlUi Team, and contributors
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ */
+
+#include "RmlUi_Platform_SFML.h"
+#include <RmlUi/Core/Context.h>
+#include <RmlUi/Core/Input.h>
+#include <RmlUi/Core/SystemInterface.h>
+#include <SFML/Graphics.hpp>
+#include <SFML/System.hpp>
+#include <SFML/Window.hpp>
+
+SystemInterface_SFML::SystemInterface_SFML()
+{
+	cursors_valid = true;
+	cursors_valid &= cursor_default.loadFromSystem(sf::Cursor::Arrow);
+	cursors_valid &= cursor_move.loadFromSystem(sf::Cursor::SizeAll);
+	cursors_valid &= cursor_pointer.loadFromSystem(sf::Cursor::Hand);
+	cursors_valid &= cursor_resize.loadFromSystem(sf::Cursor::SizeTopLeftBottomRight) || cursor_resize.loadFromSystem(sf::Cursor::SizeAll);
+	cursors_valid &= cursor_cross.loadFromSystem(sf::Cursor::Cross);
+	cursors_valid &= cursor_text.loadFromSystem(sf::Cursor::Text);
+	cursors_valid &= cursor_unavailable.loadFromSystem(sf::Cursor::NotAllowed);
+}
+
+void SystemInterface_SFML::SetWindow(sf::RenderWindow* in_window)
+{
+	window = in_window;
+}
+
+double SystemInterface_SFML::GetElapsedTime()
+{
+	return static_cast<double>(timer.getElapsedTime().asMicroseconds()) / 1'000'000.0;
+}
+
+void SystemInterface_SFML::SetMouseCursor(const Rml::String& cursor_name)
+{
+	if (cursors_valid && window)
+	{
+		sf::Cursor* cursor = nullptr;
+		if (cursor_name.empty() || cursor_name == "arrow")
+			cursor = &cursor_default;
+		else if (cursor_name == "move")
+			cursor = &cursor_move;
+		else if (cursor_name == "pointer")
+			cursor = &cursor_pointer;
+		else if (cursor_name == "resize")
+			cursor = &cursor_resize;
+		else if (cursor_name == "cross")
+			cursor = &cursor_cross;
+		else if (cursor_name == "text")
+			cursor = &cursor_text;
+		else if (cursor_name == "unavailable")
+			cursor = &cursor_unavailable;
+
+		if (cursor)
+			window->setMouseCursor(*cursor);
+	}
+}
+
+void SystemInterface_SFML::SetClipboardText(const Rml::String& text_utf8)
+{
+	sf::Clipboard::setString(text_utf8);
+}
+
+void SystemInterface_SFML::GetClipboardText(Rml::String& text)
+{
+	text = sf::Clipboard::getString();
+}
+
+bool RmlSFML::InputHandler(Rml::Context* context, sf::Event& ev)
+{
+	bool result = true;
+
+	switch (ev.type)
+	{
+	case sf::Event::MouseMoved:
+		result = context->ProcessMouseMove(ev.mouseMove.x, ev.mouseMove.y, RmlSFML::GetKeyModifierState());
+		break;
+	case sf::Event::MouseButtonPressed:
+		result = context->ProcessMouseButtonDown(ev.mouseButton.button, RmlSFML::GetKeyModifierState());
+		break;
+	case sf::Event::MouseButtonReleased:
+		result = context->ProcessMouseButtonUp(ev.mouseButton.button, RmlSFML::GetKeyModifierState());
+		break;
+	case sf::Event::MouseWheelMoved:
+		result = context->ProcessMouseWheel(float(-ev.mouseWheel.delta), RmlSFML::GetKeyModifierState());
+		break;
+	case sf::Event::TextEntered:
+	{
+		Rml::Character character = Rml::Character(ev.text.unicode);
+		if (character == Rml::Character('\r'))
+			character = Rml::Character('\n');
+
+		if (ev.text.unicode >= 32 || character == Rml::Character('\n'))
+			result = context->ProcessTextInput(character);
+	}
+	break;
+	case sf::Event::KeyPressed:
+		result = context->ProcessKeyDown(RmlSFML::ConvertKey(ev.key.code), RmlSFML::GetKeyModifierState());
+		break;
+	case sf::Event::KeyReleased:
+		result = context->ProcessKeyUp(RmlSFML::ConvertKey(ev.key.code), RmlSFML::GetKeyModifierState());
+		break;
+	default:
+		break;
+	}
+
+	return result;
+}
+
+Rml::Input::KeyIdentifier RmlSFML::ConvertKey(sf::Keyboard::Key sfml_key)
+{
+	// clang-format off
+	switch (sfml_key)
+	{
+	case sf::Keyboard::A:         return Rml::Input::KI_A;
+	case sf::Keyboard::B:         return Rml::Input::KI_B;
+	case sf::Keyboard::C:         return Rml::Input::KI_C;
+	case sf::Keyboard::D:         return Rml::Input::KI_D;
+	case sf::Keyboard::E:         return Rml::Input::KI_E;
+	case sf::Keyboard::F:         return Rml::Input::KI_F;
+	case sf::Keyboard::G:         return Rml::Input::KI_G;
+	case sf::Keyboard::H:         return Rml::Input::KI_H;
+	case sf::Keyboard::I:         return Rml::Input::KI_I;
+	case sf::Keyboard::J:         return Rml::Input::KI_J;
+	case sf::Keyboard::K:         return Rml::Input::KI_K;
+	case sf::Keyboard::L:         return Rml::Input::KI_L;
+	case sf::Keyboard::M:         return Rml::Input::KI_M;
+	case sf::Keyboard::N:         return Rml::Input::KI_N;
+	case sf::Keyboard::O:         return Rml::Input::KI_O;
+	case sf::Keyboard::P:         return Rml::Input::KI_P;
+	case sf::Keyboard::Q:         return Rml::Input::KI_Q;
+	case sf::Keyboard::R:         return Rml::Input::KI_R;
+	case sf::Keyboard::S:         return Rml::Input::KI_S;
+	case sf::Keyboard::T:         return Rml::Input::KI_T;
+	case sf::Keyboard::U:         return Rml::Input::KI_U;
+	case sf::Keyboard::V:         return Rml::Input::KI_V;
+	case sf::Keyboard::W:         return Rml::Input::KI_W;
+	case sf::Keyboard::X:         return Rml::Input::KI_X;
+	case sf::Keyboard::Y:         return Rml::Input::KI_Y;
+	case sf::Keyboard::Z:         return Rml::Input::KI_Z;
+	case sf::Keyboard::Num0:      return Rml::Input::KI_0;
+	case sf::Keyboard::Num1:      return Rml::Input::KI_1;
+	case sf::Keyboard::Num2:      return Rml::Input::KI_2;
+	case sf::Keyboard::Num3:      return Rml::Input::KI_3;
+	case sf::Keyboard::Num4:      return Rml::Input::KI_4;
+	case sf::Keyboard::Num5:      return Rml::Input::KI_5;
+	case sf::Keyboard::Num6:      return Rml::Input::KI_6;
+	case sf::Keyboard::Num7:      return Rml::Input::KI_7;
+	case sf::Keyboard::Num8:      return Rml::Input::KI_8;
+	case sf::Keyboard::Num9:      return Rml::Input::KI_9;
+	case sf::Keyboard::Numpad0:   return Rml::Input::KI_NUMPAD0;
+	case sf::Keyboard::Numpad1:   return Rml::Input::KI_NUMPAD1;
+	case sf::Keyboard::Numpad2:   return Rml::Input::KI_NUMPAD2;
+	case sf::Keyboard::Numpad3:   return Rml::Input::KI_NUMPAD3;
+	case sf::Keyboard::Numpad4:   return Rml::Input::KI_NUMPAD4;
+	case sf::Keyboard::Numpad5:   return Rml::Input::KI_NUMPAD5;
+	case sf::Keyboard::Numpad6:   return Rml::Input::KI_NUMPAD6;
+	case sf::Keyboard::Numpad7:   return Rml::Input::KI_NUMPAD7;
+	case sf::Keyboard::Numpad8:   return Rml::Input::KI_NUMPAD8;
+	case sf::Keyboard::Numpad9:   return Rml::Input::KI_NUMPAD9;
+	case sf::Keyboard::Left:      return Rml::Input::KI_LEFT;
+	case sf::Keyboard::Right:     return Rml::Input::KI_RIGHT;
+	case sf::Keyboard::Up:        return Rml::Input::KI_UP;
+	case sf::Keyboard::Down:      return Rml::Input::KI_DOWN;
+	case sf::Keyboard::Add:       return Rml::Input::KI_ADD;
+	case sf::Keyboard::BackSpace: return Rml::Input::KI_BACK;
+	case sf::Keyboard::Delete:    return Rml::Input::KI_DELETE;
+	case sf::Keyboard::Divide:    return Rml::Input::KI_DIVIDE;
+	case sf::Keyboard::End:       return Rml::Input::KI_END;
+	case sf::Keyboard::Escape:    return Rml::Input::KI_ESCAPE;
+	case sf::Keyboard::F1:        return Rml::Input::KI_F1;
+	case sf::Keyboard::F2:        return Rml::Input::KI_F2;
+	case sf::Keyboard::F3:        return Rml::Input::KI_F3;
+	case sf::Keyboard::F4:        return Rml::Input::KI_F4;
+	case sf::Keyboard::F5:        return Rml::Input::KI_F5;
+	case sf::Keyboard::F6:        return Rml::Input::KI_F6;
+	case sf::Keyboard::F7:        return Rml::Input::KI_F7;
+	case sf::Keyboard::F8:        return Rml::Input::KI_F8;
+	case sf::Keyboard::F9:        return Rml::Input::KI_F9;
+	case sf::Keyboard::F10:       return Rml::Input::KI_F10;
+	case sf::Keyboard::F11:       return Rml::Input::KI_F11;
+	case sf::Keyboard::F12:       return Rml::Input::KI_F12;
+	case sf::Keyboard::F13:       return Rml::Input::KI_F13;
+	case sf::Keyboard::F14:       return Rml::Input::KI_F14;
+	case sf::Keyboard::F15:       return Rml::Input::KI_F15;
+	case sf::Keyboard::Home:      return Rml::Input::KI_HOME;
+	case sf::Keyboard::Insert:    return Rml::Input::KI_INSERT;
+	case sf::Keyboard::LControl:  return Rml::Input::KI_LCONTROL;
+	case sf::Keyboard::LShift:    return Rml::Input::KI_LSHIFT;
+	case sf::Keyboard::Multiply:  return Rml::Input::KI_MULTIPLY;
+	case sf::Keyboard::Pause:     return Rml::Input::KI_PAUSE;
+	case sf::Keyboard::RControl:  return Rml::Input::KI_RCONTROL;
+	case sf::Keyboard::Return:    return Rml::Input::KI_RETURN;
+	case sf::Keyboard::RShift:    return Rml::Input::KI_RSHIFT;
+	case sf::Keyboard::Space:     return Rml::Input::KI_SPACE;
+	case sf::Keyboard::Subtract:  return Rml::Input::KI_SUBTRACT;
+	case sf::Keyboard::Tab:       return Rml::Input::KI_TAB;
+	default: break;
+	}
+	// clang-format on
+
+	return Rml::Input::KI_UNKNOWN;
+}
+
+int RmlSFML::GetKeyModifierState()
+{
+	int modifiers = 0;
+
+	if (sf::Keyboard::isKeyPressed(sf::Keyboard::LShift) || sf::Keyboard::isKeyPressed(sf::Keyboard::RShift))
+		modifiers |= Rml::Input::KM_SHIFT;
+
+	if (sf::Keyboard::isKeyPressed(sf::Keyboard::LControl) || sf::Keyboard::isKeyPressed(sf::Keyboard::RControl))
+		modifiers |= Rml::Input::KM_CTRL;
+
+	if (sf::Keyboard::isKeyPressed(sf::Keyboard::LAlt) || sf::Keyboard::isKeyPressed(sf::Keyboard::RAlt))
+		modifiers |= Rml::Input::KM_ALT;
+
+	return modifiers;
+}

+ 88 - 0
Backends/RmlUi_Platform_SFML.h

@@ -0,0 +1,88 @@
+/*
+ * This source file is part of RmlUi, the HTML/CSS Interface Middleware
+ *
+ * For the latest information, see http://github.com/mikke89/RmlUi
+ *
+ * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd
+ * Copyright (c) 2019 The RmlUi Team, and contributors
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ */
+
+#ifndef RMLUI_BACKENDS_PLATFORM_SFML_H
+#define RMLUI_BACKENDS_PLATFORM_SFML_H
+
+#include <RmlUi/Core/Input.h>
+#include <RmlUi/Core/SystemInterface.h>
+#include <RmlUi/Core/Types.h>
+#include <SFML/Graphics.hpp>
+#include <SFML/System.hpp>
+#include <SFML/Window.hpp>
+
+class SystemInterface_SFML : public Rml::SystemInterface {
+public:
+	SystemInterface_SFML();
+
+	// Optionally, provide or change the window to be used for setting the mouse cursors.
+	// @lifetime Any window provided here must be destroyed before the system interface.
+	// @lifetime The currently active window must stay alive until after the call to Rml::Shutdown. 
+	void SetWindow(sf::RenderWindow* window);
+
+	// -- Inherited from Rml::SystemInterface  --
+
+	double GetElapsedTime() override;
+
+	void SetMouseCursor(const Rml::String& cursor_name) override;
+
+	void SetClipboardText(const Rml::String& text) override;
+	void GetClipboardText(Rml::String& text) override;
+
+private:
+	sf::Clock timer;
+	sf::RenderWindow* window = nullptr;
+
+	bool cursors_valid = false;
+	sf::Cursor cursor_default;
+	sf::Cursor cursor_move;
+	sf::Cursor cursor_pointer;
+	sf::Cursor cursor_resize;
+	sf::Cursor cursor_cross;
+	sf::Cursor cursor_text;
+	sf::Cursor cursor_unavailable;
+};
+
+/**
+    Optional helper functions for the SFML plaform.
+ */
+namespace RmlSFML {
+
+// Applies input on the context based on the given SFML event.
+// @return True if the event is still propagating, false if it was handled by the context.
+bool InputHandler(Rml::Context* context, sf::Event& ev);
+
+// Converts the SFML key to RmlUi key.
+Rml::Input::KeyIdentifier ConvertKey(sf::Keyboard::Key sfml_key);
+
+// Returns the active RmlUi key modifier state.
+int GetKeyModifierState();
+
+} // namespace RmlSFML
+
+#endif

+ 482 - 0
Backends/RmlUi_Platform_Win32.cpp

@@ -0,0 +1,482 @@
+/*
+ * This source file is part of RmlUi, the HTML/CSS Interface Middleware
+ *
+ * For the latest information, see http://github.com/mikke89/RmlUi
+ *
+ * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd
+ * Copyright (c) 2019 The RmlUi Team, and contributors
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ */
+
+#include "RmlUi_Platform_Win32.h"
+#include "RmlUi_Include_Windows.h"
+#include <RmlUi/Core/Context.h>
+#include <RmlUi/Core/Input.h>
+#include <RmlUi/Core/StringUtilities.h>
+#include <RmlUi/Core/SystemInterface.h>
+#include <string.h>
+
+SystemInterface_Win32::SystemInterface_Win32()
+{
+	LARGE_INTEGER time_ticks_per_second;
+	QueryPerformanceFrequency(&time_ticks_per_second);
+	QueryPerformanceCounter(&time_startup);
+
+	time_frequency = 1.0 / (double)time_ticks_per_second.QuadPart;
+
+	// Load cursors
+	cursor_default = LoadCursor(nullptr, IDC_ARROW);
+	cursor_move = LoadCursor(nullptr, IDC_SIZEALL);
+	cursor_pointer = LoadCursor(nullptr, IDC_HAND);
+	cursor_resize = LoadCursor(nullptr, IDC_SIZENWSE);
+	cursor_cross = LoadCursor(nullptr, IDC_CROSS);
+	cursor_text = LoadCursor(nullptr, IDC_IBEAM);
+	cursor_unavailable = LoadCursor(nullptr, IDC_NO);
+}
+
+void SystemInterface_Win32::SetWindow(HWND in_window_handle)
+{
+	window_handle = in_window_handle;
+}
+
+double SystemInterface_Win32::GetElapsedTime()
+{
+	LARGE_INTEGER counter;
+	QueryPerformanceCounter(&counter);
+
+	return double(counter.QuadPart - time_startup.QuadPart) * time_frequency;
+}
+
+void SystemInterface_Win32::SetMouseCursor(const Rml::String& cursor_name)
+{
+	if (window_handle)
+	{
+		HCURSOR cursor_handle = nullptr;
+		if (cursor_name.empty() || cursor_name == "arrow")
+			cursor_handle = cursor_default;
+		else if (cursor_name == "move")
+			cursor_handle = cursor_move;
+		else if (cursor_name == "pointer")
+			cursor_handle = cursor_pointer;
+		else if (cursor_name == "resize")
+			cursor_handle = cursor_resize;
+		else if (cursor_name == "cross")
+			cursor_handle = cursor_cross;
+		else if (cursor_name == "text")
+			cursor_handle = cursor_text;
+		else if (cursor_name == "unavailable")
+			cursor_handle = cursor_unavailable;
+
+		if (cursor_handle)
+		{
+			SetCursor(cursor_handle);
+			SetClassLongPtrA(window_handle, GCLP_HCURSOR, (LONG_PTR)cursor_handle);
+		}
+	}
+}
+
+void SystemInterface_Win32::SetClipboardText(const Rml::String& text_utf8)
+{
+	if (window_handle)
+	{
+		if (!OpenClipboard(window_handle))
+			return;
+
+		EmptyClipboard();
+
+		const std::wstring text = RmlWin32::ConvertToUTF16(text_utf8);
+		const size_t size = sizeof(wchar_t) * (text.size() + 1);
+
+		HGLOBAL clipboard_data = GlobalAlloc(GMEM_FIXED, size);
+		memcpy(clipboard_data, text.data(), size);
+
+		if (SetClipboardData(CF_UNICODETEXT, clipboard_data) == nullptr)
+		{
+			CloseClipboard();
+			GlobalFree(clipboard_data);
+		}
+		else
+			CloseClipboard();
+	}
+}
+
+void SystemInterface_Win32::GetClipboardText(Rml::String& text)
+{
+	if (window_handle)
+	{
+		if (!OpenClipboard(window_handle))
+			return;
+
+		HANDLE clipboard_data = GetClipboardData(CF_UNICODETEXT);
+		if (clipboard_data == nullptr)
+		{
+			CloseClipboard();
+			return;
+		}
+
+		const wchar_t* clipboard_text = (const wchar_t*)GlobalLock(clipboard_data);
+		if (clipboard_text)
+			text = RmlWin32::ConvertToUTF8(clipboard_text);
+		GlobalUnlock(clipboard_data);
+
+		CloseClipboard();
+	}
+}
+
+Rml::String RmlWin32::ConvertToUTF8(const std::wstring& wstr)
+{
+	const int count = WideCharToMultiByte(CP_UTF8, 0, wstr.c_str(), (int)wstr.length(), NULL, 0, NULL, NULL);
+	Rml::String str(count, 0);
+	WideCharToMultiByte(CP_UTF8, 0, wstr.c_str(), -1, &str[0], count, NULL, NULL);
+	return str;
+}
+
+std::wstring RmlWin32::ConvertToUTF16(const Rml::String& str)
+{
+	const int count = MultiByteToWideChar(CP_UTF8, 0, str.c_str(), (int)str.length(), NULL, 0);
+	std::wstring wstr(count, 0);
+	MultiByteToWideChar(CP_UTF8, 0, str.c_str(), (int)str.length(), &wstr[0], count);
+	return wstr;
+}
+
+bool RmlWin32::WindowProcedure(Rml::Context* context, HWND window_handle, UINT message, WPARAM w_param, LPARAM l_param)
+{
+	if (!context)
+		return true;
+
+	bool result = true;
+
+	switch (message)
+	{
+	case WM_LBUTTONDOWN:
+		result = context->ProcessMouseButtonDown(0, RmlWin32::GetKeyModifierState());
+		SetCapture(window_handle);
+		break;
+	case WM_LBUTTONUP:
+		ReleaseCapture();
+		result = context->ProcessMouseButtonUp(0, RmlWin32::GetKeyModifierState());
+		break;
+	case WM_RBUTTONDOWN:
+		result = context->ProcessMouseButtonDown(1, RmlWin32::GetKeyModifierState());
+		break;
+	case WM_RBUTTONUP:
+		result = context->ProcessMouseButtonUp(1, RmlWin32::GetKeyModifierState());
+		break;
+	case WM_MBUTTONDOWN:
+		result = context->ProcessMouseButtonDown(2, RmlWin32::GetKeyModifierState());
+		break;
+	case WM_MBUTTONUP:
+		result = context->ProcessMouseButtonUp(2, RmlWin32::GetKeyModifierState());
+		break;
+	case WM_MOUSEMOVE:
+		result = context->ProcessMouseMove(static_cast<int>((short)LOWORD(l_param)), static_cast<int>((short)HIWORD(l_param)),
+			RmlWin32::GetKeyModifierState());
+		break;
+	case WM_MOUSEWHEEL:
+		result = context->ProcessMouseWheel(static_cast<float>((short)HIWORD(w_param)) / static_cast<float>(-WHEEL_DELTA),
+			RmlWin32::GetKeyModifierState());
+		break;
+	case WM_KEYDOWN:
+		result = context->ProcessKeyDown(RmlWin32::ConvertKey((int)w_param), RmlWin32::GetKeyModifierState());
+		break;
+	case WM_KEYUP:
+		result = context->ProcessKeyUp(RmlWin32::ConvertKey((int)w_param), RmlWin32::GetKeyModifierState());
+		break;
+	case WM_CHAR:
+	{
+		static wchar_t first_u16_code_unit = 0;
+
+		const wchar_t c = (wchar_t)w_param;
+		Rml::Character character = (Rml::Character)c;
+
+		// Windows sends two-wide characters as two messages.
+		if (c >= 0xD800 && c < 0xDC00)
+		{
+			// First 16-bit code unit of a two-wide character.
+			first_u16_code_unit = c;
+		}
+		else
+		{
+			if (c >= 0xDC00 && c < 0xE000 && first_u16_code_unit != 0)
+			{
+				// Second 16-bit code unit of a two-wide character.
+				Rml::String utf8 = ConvertToUTF8(std::wstring{first_u16_code_unit, c});
+				character = Rml::StringUtilities::ToCharacter(utf8.data());
+			}
+			else if (c == '\r')
+			{
+				// Windows sends new-lines as carriage returns, convert to endlines.
+				character = (Rml::Character)'\n';
+			}
+
+			first_u16_code_unit = 0;
+
+			// Only send through printable characters.
+			if (((char32_t)character >= 32 || character == (Rml::Character)'\n') && character != (Rml::Character)127)
+				result = context->ProcessTextInput(character);
+		}
+	}
+	break;
+	default:
+		break;
+	}
+
+	return result;
+}
+
+int RmlWin32::GetKeyModifierState()
+{
+	int key_modifier_state = 0;
+
+	if (GetKeyState(VK_CAPITAL) & 1)
+		key_modifier_state |= Rml::Input::KM_CAPSLOCK;
+
+	if (GetKeyState(VK_NUMLOCK) & 1)
+		key_modifier_state |= Rml::Input::KM_NUMLOCK;
+
+	if (HIWORD(GetKeyState(VK_SHIFT)) & 1)
+		key_modifier_state |= Rml::Input::KM_SHIFT;
+
+	if (HIWORD(GetKeyState(VK_CONTROL)) & 1)
+		key_modifier_state |= Rml::Input::KM_CTRL;
+
+	if (HIWORD(GetKeyState(VK_MENU)) & 1)
+		key_modifier_state |= Rml::Input::KM_ALT;
+
+	return key_modifier_state;
+}
+
+// These are defined in winuser.h of MinGW 64 but are missing from MinGW 32
+// Visual Studio has them by default
+#if defined(__MINGW32__) && !defined(__MINGW64__)
+	#define VK_OEM_NEC_EQUAL 0x92
+	#define VK_OEM_FJ_JISHO 0x92
+	#define VK_OEM_FJ_MASSHOU 0x93
+	#define VK_OEM_FJ_TOUROKU 0x94
+	#define VK_OEM_FJ_LOYA 0x95
+	#define VK_OEM_FJ_ROYA 0x96
+	#define VK_OEM_AX 0xE1
+	#define VK_ICO_HELP 0xE3
+	#define VK_ICO_00 0xE4
+	#define VK_ICO_CLEAR 0xE6
+#endif // !defined(__MINGW32__)  || defined(__MINGW64__)
+
+Rml::Input::KeyIdentifier RmlWin32::ConvertKey(int win32_key_code)
+{
+	// clang-format off
+	switch (win32_key_code)
+	{
+		case 'A':                    return Rml::Input::KI_A;
+		case 'B':                    return Rml::Input::KI_B;
+		case 'C':                    return Rml::Input::KI_C;
+		case 'D':                    return Rml::Input::KI_D;
+		case 'E':                    return Rml::Input::KI_E;
+		case 'F':                    return Rml::Input::KI_F;
+		case 'G':                    return Rml::Input::KI_G;
+		case 'H':                    return Rml::Input::KI_H;
+		case 'I':                    return Rml::Input::KI_I;
+		case 'J':                    return Rml::Input::KI_J;
+		case 'K':                    return Rml::Input::KI_K;
+		case 'L':                    return Rml::Input::KI_L;
+		case 'M':                    return Rml::Input::KI_M;
+		case 'N':                    return Rml::Input::KI_N;
+		case 'O':                    return Rml::Input::KI_O;
+		case 'P':                    return Rml::Input::KI_P;
+		case 'Q':                    return Rml::Input::KI_Q;
+		case 'R':                    return Rml::Input::KI_R;
+		case 'S':                    return Rml::Input::KI_S;
+		case 'T':                    return Rml::Input::KI_T;
+		case 'U':                    return Rml::Input::KI_U;
+		case 'V':                    return Rml::Input::KI_V;
+		case 'W':                    return Rml::Input::KI_W;
+		case 'X':                    return Rml::Input::KI_X;
+		case 'Y':                    return Rml::Input::KI_Y;
+		case 'Z':                    return Rml::Input::KI_Z;
+
+		case '0':                    return Rml::Input::KI_0;
+		case '1':                    return Rml::Input::KI_1;
+		case '2':                    return Rml::Input::KI_2;
+		case '3':                    return Rml::Input::KI_3;
+		case '4':                    return Rml::Input::KI_4;
+		case '5':                    return Rml::Input::KI_5;
+		case '6':                    return Rml::Input::KI_6;
+		case '7':                    return Rml::Input::KI_7;
+		case '8':                    return Rml::Input::KI_8;
+		case '9':                    return Rml::Input::KI_9;
+
+		case VK_BACK:                return Rml::Input::KI_BACK;
+		case VK_TAB:                 return Rml::Input::KI_TAB;
+
+		case VK_CLEAR:               return Rml::Input::KI_CLEAR;
+		case VK_RETURN:              return Rml::Input::KI_RETURN;
+
+		case VK_PAUSE:               return Rml::Input::KI_PAUSE;
+		case VK_CAPITAL:             return Rml::Input::KI_CAPITAL;
+
+		case VK_KANA:                return Rml::Input::KI_KANA;
+		//case VK_HANGUL:              return Rml::Input::KI_HANGUL; /* overlaps with VK_KANA */
+		case VK_JUNJA:               return Rml::Input::KI_JUNJA;
+		case VK_FINAL:               return Rml::Input::KI_FINAL;
+		case VK_HANJA:               return Rml::Input::KI_HANJA;
+		//case VK_KANJI:               return Rml::Input::KI_KANJI; /* overlaps with VK_HANJA */
+
+		case VK_ESCAPE:              return Rml::Input::KI_ESCAPE;
+
+		case VK_CONVERT:             return Rml::Input::KI_CONVERT;
+		case VK_NONCONVERT:          return Rml::Input::KI_NONCONVERT;
+		case VK_ACCEPT:              return Rml::Input::KI_ACCEPT;
+		case VK_MODECHANGE:          return Rml::Input::KI_MODECHANGE;
+
+		case VK_SPACE:               return Rml::Input::KI_SPACE;
+		case VK_PRIOR:               return Rml::Input::KI_PRIOR;
+		case VK_NEXT:                return Rml::Input::KI_NEXT;
+		case VK_END:                 return Rml::Input::KI_END;
+		case VK_HOME:                return Rml::Input::KI_HOME;
+		case VK_LEFT:                return Rml::Input::KI_LEFT;
+		case VK_UP:                  return Rml::Input::KI_UP;
+		case VK_RIGHT:               return Rml::Input::KI_RIGHT;
+		case VK_DOWN:                return Rml::Input::KI_DOWN;
+		case VK_SELECT:              return Rml::Input::KI_SELECT;
+		case VK_PRINT:               return Rml::Input::KI_PRINT;
+		case VK_EXECUTE:             return Rml::Input::KI_EXECUTE;
+		case VK_SNAPSHOT:            return Rml::Input::KI_SNAPSHOT;
+		case VK_INSERT:              return Rml::Input::KI_INSERT;
+		case VK_DELETE:              return Rml::Input::KI_DELETE;
+		case VK_HELP:                return Rml::Input::KI_HELP;
+
+		case VK_LWIN:                return Rml::Input::KI_LWIN;
+		case VK_RWIN:                return Rml::Input::KI_RWIN;
+		case VK_APPS:                return Rml::Input::KI_APPS;
+
+		case VK_SLEEP:               return Rml::Input::KI_SLEEP;
+
+		case VK_NUMPAD0:             return Rml::Input::KI_NUMPAD0;
+		case VK_NUMPAD1:             return Rml::Input::KI_NUMPAD1;
+		case VK_NUMPAD2:             return Rml::Input::KI_NUMPAD2;
+		case VK_NUMPAD3:             return Rml::Input::KI_NUMPAD3;
+		case VK_NUMPAD4:             return Rml::Input::KI_NUMPAD4;
+		case VK_NUMPAD5:             return Rml::Input::KI_NUMPAD5;
+		case VK_NUMPAD6:             return Rml::Input::KI_NUMPAD6;
+		case VK_NUMPAD7:             return Rml::Input::KI_NUMPAD7;
+		case VK_NUMPAD8:             return Rml::Input::KI_NUMPAD8;
+		case VK_NUMPAD9:             return Rml::Input::KI_NUMPAD9;
+		case VK_MULTIPLY:            return Rml::Input::KI_MULTIPLY;
+		case VK_ADD:                 return Rml::Input::KI_ADD;
+		case VK_SEPARATOR:           return Rml::Input::KI_SEPARATOR;
+		case VK_SUBTRACT:            return Rml::Input::KI_SUBTRACT;
+		case VK_DECIMAL:             return Rml::Input::KI_DECIMAL;
+		case VK_DIVIDE:              return Rml::Input::KI_DIVIDE;
+		case VK_F1:                  return Rml::Input::KI_F1;
+		case VK_F2:                  return Rml::Input::KI_F2;
+		case VK_F3:                  return Rml::Input::KI_F3;
+		case VK_F4:                  return Rml::Input::KI_F4;
+		case VK_F5:                  return Rml::Input::KI_F5;
+		case VK_F6:                  return Rml::Input::KI_F6;
+		case VK_F7:                  return Rml::Input::KI_F7;
+		case VK_F8:                  return Rml::Input::KI_F8;
+		case VK_F9:                  return Rml::Input::KI_F9;
+		case VK_F10:                 return Rml::Input::KI_F10;
+		case VK_F11:                 return Rml::Input::KI_F11;
+		case VK_F12:                 return Rml::Input::KI_F12;
+		case VK_F13:                 return Rml::Input::KI_F13;
+		case VK_F14:                 return Rml::Input::KI_F14;
+		case VK_F15:                 return Rml::Input::KI_F15;
+		case VK_F16:                 return Rml::Input::KI_F16;
+		case VK_F17:                 return Rml::Input::KI_F17;
+		case VK_F18:                 return Rml::Input::KI_F18;
+		case VK_F19:                 return Rml::Input::KI_F19;
+		case VK_F20:                 return Rml::Input::KI_F20;
+		case VK_F21:                 return Rml::Input::KI_F21;
+		case VK_F22:                 return Rml::Input::KI_F22;
+		case VK_F23:                 return Rml::Input::KI_F23;
+		case VK_F24:                 return Rml::Input::KI_F24;
+
+		case VK_NUMLOCK:             return Rml::Input::KI_NUMLOCK;
+		case VK_SCROLL:              return Rml::Input::KI_SCROLL;
+
+		case VK_OEM_NEC_EQUAL:       return Rml::Input::KI_OEM_NEC_EQUAL;
+
+		//case VK_OEM_FJ_JISHO:        return Rml::Input::KI_OEM_FJ_JISHO; /* overlaps with VK_OEM_NEC_EQUAL */
+		case VK_OEM_FJ_MASSHOU:      return Rml::Input::KI_OEM_FJ_MASSHOU;
+		case VK_OEM_FJ_TOUROKU:      return Rml::Input::KI_OEM_FJ_TOUROKU;
+		case VK_OEM_FJ_LOYA:         return Rml::Input::KI_OEM_FJ_LOYA;
+		case VK_OEM_FJ_ROYA:         return Rml::Input::KI_OEM_FJ_ROYA;
+
+		case VK_SHIFT:               return Rml::Input::KI_LSHIFT;
+		case VK_CONTROL:             return Rml::Input::KI_LCONTROL;
+		case VK_MENU:                return Rml::Input::KI_LMENU;
+
+		case VK_BROWSER_BACK:        return Rml::Input::KI_BROWSER_BACK;
+		case VK_BROWSER_FORWARD:     return Rml::Input::KI_BROWSER_FORWARD;
+		case VK_BROWSER_REFRESH:     return Rml::Input::KI_BROWSER_REFRESH;
+		case VK_BROWSER_STOP:        return Rml::Input::KI_BROWSER_STOP;
+		case VK_BROWSER_SEARCH:      return Rml::Input::KI_BROWSER_SEARCH;
+		case VK_BROWSER_FAVORITES:   return Rml::Input::KI_BROWSER_FAVORITES;
+		case VK_BROWSER_HOME:        return Rml::Input::KI_BROWSER_HOME;
+
+		case VK_VOLUME_MUTE:         return Rml::Input::KI_VOLUME_MUTE;
+		case VK_VOLUME_DOWN:         return Rml::Input::KI_VOLUME_DOWN;
+		case VK_VOLUME_UP:           return Rml::Input::KI_VOLUME_UP;
+		case VK_MEDIA_NEXT_TRACK:    return Rml::Input::KI_MEDIA_NEXT_TRACK;
+		case VK_MEDIA_PREV_TRACK:    return Rml::Input::KI_MEDIA_PREV_TRACK;
+		case VK_MEDIA_STOP:          return Rml::Input::KI_MEDIA_STOP;
+		case VK_MEDIA_PLAY_PAUSE:    return Rml::Input::KI_MEDIA_PLAY_PAUSE;
+		case VK_LAUNCH_MAIL:         return Rml::Input::KI_LAUNCH_MAIL;
+		case VK_LAUNCH_MEDIA_SELECT: return Rml::Input::KI_LAUNCH_MEDIA_SELECT;
+		case VK_LAUNCH_APP1:         return Rml::Input::KI_LAUNCH_APP1;
+		case VK_LAUNCH_APP2:         return Rml::Input::KI_LAUNCH_APP2;
+
+		case VK_OEM_1:               return Rml::Input::KI_OEM_1;
+		case VK_OEM_PLUS:            return Rml::Input::KI_OEM_PLUS;
+		case VK_OEM_COMMA:           return Rml::Input::KI_OEM_COMMA;
+		case VK_OEM_MINUS:           return Rml::Input::KI_OEM_MINUS;
+		case VK_OEM_PERIOD:          return Rml::Input::KI_OEM_PERIOD;
+		case VK_OEM_2:               return Rml::Input::KI_OEM_2;
+		case VK_OEM_3:               return Rml::Input::KI_OEM_3;
+
+		case VK_OEM_4:               return Rml::Input::KI_OEM_4;
+		case VK_OEM_5:               return Rml::Input::KI_OEM_5;
+		case VK_OEM_6:               return Rml::Input::KI_OEM_6;
+		case VK_OEM_7:               return Rml::Input::KI_OEM_7;
+		case VK_OEM_8:               return Rml::Input::KI_OEM_8;
+
+		case VK_OEM_AX:              return Rml::Input::KI_OEM_AX;
+		case VK_OEM_102:             return Rml::Input::KI_OEM_102;
+		case VK_ICO_HELP:            return Rml::Input::KI_ICO_HELP;
+		case VK_ICO_00:              return Rml::Input::KI_ICO_00;
+
+		case VK_PROCESSKEY:          return Rml::Input::KI_PROCESSKEY;
+
+		case VK_ICO_CLEAR:           return Rml::Input::KI_ICO_CLEAR;
+
+		case VK_ATTN:                return Rml::Input::KI_ATTN;
+		case VK_CRSEL:               return Rml::Input::KI_CRSEL;
+		case VK_EXSEL:               return Rml::Input::KI_EXSEL;
+		case VK_EREOF:               return Rml::Input::KI_EREOF;
+		case VK_PLAY:                return Rml::Input::KI_PLAY;
+		case VK_ZOOM:                return Rml::Input::KI_ZOOM;
+		case VK_PA1:                 return Rml::Input::KI_PA1;
+		case VK_OEM_CLEAR:           return Rml::Input::KI_OEM_CLEAR;
+	}
+	// clang-format on
+
+	return Rml::Input::KI_UNKNOWN;
+}

+ 90 - 0
Backends/RmlUi_Platform_Win32.h

@@ -0,0 +1,90 @@
+/*
+ * This source file is part of RmlUi, the HTML/CSS Interface Middleware
+ *
+ * For the latest information, see http://github.com/mikke89/RmlUi
+ *
+ * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd
+ * Copyright (c) 2019 The RmlUi Team, and contributors
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ */
+
+#ifndef RMLUI_BACKENDS_PLATFORM_WIN32_H
+#define RMLUI_BACKENDS_PLATFORM_WIN32_H
+
+#include "RmlUi_Include_Windows.h"
+#include <RmlUi/Core/Input.h>
+#include <RmlUi/Core/SystemInterface.h>
+#include <RmlUi/Core/Types.h>
+#include <string>
+
+class SystemInterface_Win32 : public Rml::SystemInterface {
+public:
+	SystemInterface_Win32();
+
+	// Optionally, provide or change the window to be used for setting the mouse cursors and clipboard text.
+	void SetWindow(HWND window_handle);
+
+	// -- Inherited from Rml::SystemInterface  --
+
+	double GetElapsedTime() override;
+
+	void SetMouseCursor(const Rml::String& cursor_name) override;
+
+	void SetClipboardText(const Rml::String& text) override;
+	void GetClipboardText(Rml::String& text) override;
+
+private:
+	HWND window_handle = nullptr;
+
+	double time_frequency = {};
+	LARGE_INTEGER time_startup = {};
+
+	HCURSOR cursor_default = nullptr;
+	HCURSOR cursor_move = nullptr;
+	HCURSOR cursor_pointer = nullptr;
+	HCURSOR cursor_resize = nullptr;
+	HCURSOR cursor_cross = nullptr;
+	HCURSOR cursor_text = nullptr;
+	HCURSOR cursor_unavailable = nullptr;
+};
+
+/**
+    Optional helper functions for the Win32 plaform.
+ */
+namespace RmlWin32 {
+
+// Convenience helpers for converting between RmlUi strings (UTF-8) and Windows strings (UTF-16).
+Rml::String ConvertToUTF8(const std::wstring& wstr);
+std::wstring ConvertToUTF16(const Rml::String& str);
+
+// Window event handler to submit default input behavior to the context.
+// @return True if the event is still propagating, false if it was handled by the context.
+bool WindowProcedure(Rml::Context* context, HWND window_handle, UINT message, WPARAM w_param, LPARAM l_param);
+
+// Converts the key from Win32 key code to RmlUi key.
+Rml::Input::KeyIdentifier ConvertKey(int win32_key_code);
+
+// Returns the active RmlUi key modifier state.
+int GetKeyModifierState();
+
+} // namespace RmlWin32
+
+#endif

+ 638 - 0
Backends/RmlUi_Platform_X11.cpp

@@ -0,0 +1,638 @@
+/*
+ * This source file is part of RmlUi, the HTML/CSS Interface Middleware
+ *
+ * For the latest information, see http://github.com/mikke89/RmlUi
+ *
+ * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd
+ * Copyright (c) 2019 The RmlUi Team, and contributors
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ */
+
+#include "RmlUi_Platform_X11.h"
+#include <RmlUi/Core/Context.h>
+#include <RmlUi/Core/Core.h>
+#include <RmlUi/Core/Input.h>
+#include <RmlUi/Core/Types.h>
+#include <X11/cursorfont.h>
+#include <X11/extensions/xf86vmode.h>
+#include <limits.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <time.h>
+#include <unistd.h>
+
+#ifdef HAS_X11XKBLIB
+	#include <X11/XKBlib.h>
+#endif // HAS_X11XKBLIB
+#include <X11/keysym.h>
+
+static Rml::Character GetCharacterCode(Rml::Input::KeyIdentifier key_identifier, int key_modifier_state);
+
+SystemInterface_X11::SystemInterface_X11(Display* display) : display(display)
+{
+	// Create cursors
+	cursor_default = XCreateFontCursor(display, XC_left_ptr);
+	cursor_move = XCreateFontCursor(display, XC_fleur);
+	cursor_pointer = XCreateFontCursor(display, XC_hand1);
+	cursor_resize = XCreateFontCursor(display, XC_sizing);
+	cursor_cross = XCreateFontCursor(display, XC_crosshair);
+	cursor_text = XCreateFontCursor(display, XC_xterm);
+	cursor_unavailable = XCreateFontCursor(display, XC_X_cursor);
+
+	// For copy & paste functions
+	UTF8_atom = XInternAtom(display, "UTF8_STRING", 1);
+	XSEL_DATA_atom = XInternAtom(display, "XSEL_DATA", 0);
+	CLIPBOARD_atom = XInternAtom(display, "CLIPBOARD", 0);
+	TARGETS_atom = XInternAtom(display, "TARGETS", 0);
+	TEXT_atom = XInternAtom(display, "TEXT", 0);
+
+	gettimeofday(&start_time, nullptr);
+}
+
+void SystemInterface_X11::SetWindow(Window in_window)
+{
+	window = in_window;
+}
+
+bool SystemInterface_X11::HandleSelectionRequest(const XEvent& ev)
+{
+	if (ev.type == SelectionRequest && XGetSelectionOwner(display, CLIPBOARD_atom) == window && ev.xselectionrequest.selection == CLIPBOARD_atom)
+	{
+		XCopy(clipboard_text, ev);
+		return false;
+	}
+	return true;
+}
+
+double SystemInterface_X11::GetElapsedTime()
+{
+	struct timeval now;
+
+	gettimeofday(&now, nullptr);
+
+	double sec = now.tv_sec - start_time.tv_sec;
+	double usec = now.tv_usec - start_time.tv_usec;
+	double result = sec + (usec / 1000000.0);
+
+	return result;
+}
+
+void SystemInterface_X11::SetMouseCursor(const Rml::String& cursor_name)
+{
+	if (display && window)
+	{
+		Cursor cursor_handle = 0;
+		if (cursor_name.empty() || cursor_name == "arrow")
+			cursor_handle = cursor_default;
+		else if (cursor_name == "move")
+			cursor_handle = cursor_move;
+		else if (cursor_name == "pointer")
+			cursor_handle = cursor_pointer;
+		else if (cursor_name == "resize")
+			cursor_handle = cursor_resize;
+		else if (cursor_name == "cross")
+			cursor_handle = cursor_cross;
+		else if (cursor_name == "text")
+			cursor_handle = cursor_text;
+		else if (cursor_name == "unavailable")
+			cursor_handle = cursor_unavailable;
+
+		if (cursor_handle)
+		{
+			XDefineCursor(display, window, cursor_handle);
+		}
+	}
+}
+
+void SystemInterface_X11::SetClipboardText(const Rml::String& text)
+{
+	clipboard_text = text;
+	XSetSelectionOwner(display, CLIPBOARD_atom, window, 0);
+}
+
+void SystemInterface_X11::GetClipboardText(Rml::String& text)
+{
+	if (XGetSelectionOwner(display, CLIPBOARD_atom) != window)
+	{
+		if (!UTF8_atom || !XPaste(UTF8_atom, text))
+		{
+			// fallback
+			XPaste(XA_STRING_atom, text);
+		}
+	}
+	else
+	{
+		text = clipboard_text;
+	}
+}
+
+void SystemInterface_X11::XCopy(const Rml::String& clipboard_data, const XEvent& event)
+{
+	Atom format = (UTF8_atom ? UTF8_atom : XA_STRING_atom);
+
+	XSelectionEvent ev = {
+		SelectionNotify, // the event type that will be sent to the requestor
+		0,               // serial
+		0,               // send_event
+		event.xselectionrequest.display, event.xselectionrequest.requestor, event.xselectionrequest.selection, event.xselectionrequest.target,
+		event.xselectionrequest.property,
+		0 // time
+	};
+
+	int retval = 0;
+	if (ev.target == TARGETS_atom)
+	{
+		retval = XChangeProperty(ev.display, ev.requestor, ev.property, XA_atom, 32, PropModeReplace, (unsigned char*)&format, 1);
+	}
+	else if (ev.target == XA_STRING_atom || ev.target == TEXT_atom)
+	{
+		retval = XChangeProperty(ev.display, ev.requestor, ev.property, XA_STRING_atom, 8, PropModeReplace, (unsigned char*)clipboard_data.c_str(),
+			clipboard_data.size());
+	}
+	else if (ev.target == UTF8_atom)
+	{
+		retval = XChangeProperty(ev.display, ev.requestor, ev.property, UTF8_atom, 8, PropModeReplace, (unsigned char*)clipboard_data.c_str(),
+			clipboard_data.size());
+	}
+	else
+	{
+		ev.property = 0;
+	}
+
+	if ((retval & 2) == 0)
+	{
+		// Notify the requestor that clipboard data is available
+		XSendEvent(display, ev.requestor, 0, 0, (XEvent*)&ev);
+	}
+}
+
+bool SystemInterface_X11::XPaste(Atom target_atom, Rml::String& clipboard_data)
+{
+	XEvent ev;
+
+	// A SelectionRequest event will be sent to the clipboard owner, which should respond with SelectionNotify
+	XConvertSelection(display, CLIPBOARD_atom, target_atom, XSEL_DATA_atom, window, CurrentTime);
+	XSync(display, 0);
+	XNextEvent(display, &ev);
+
+	if (ev.type == SelectionNotify)
+	{
+		if (ev.xselection.property == 0)
+		{
+			// If no owner for the specified selection exists, the X server generates
+			// a SelectionNotify event with property None (0).
+			return false;
+		}
+		if (ev.xselection.selection == CLIPBOARD_atom)
+		{
+			int actual_format;
+			unsigned long bytes_after, nitems;
+			char* prop = nullptr;
+			Atom actual_type;
+			XGetWindowProperty(ev.xselection.display, ev.xselection.requestor, ev.xselection.property,
+				0L,    // offset
+				(~0L), // length
+				0,     // delete?
+				AnyPropertyType, &actual_type, &actual_format, &nitems, &bytes_after, (unsigned char**)&prop);
+
+			if (actual_type == UTF8_atom || actual_type == XA_STRING_atom)
+			{
+				clipboard_data = Rml::String(prop, prop + nitems);
+				XFree(prop);
+			}
+
+			XDeleteProperty(ev.xselection.display, ev.xselection.requestor, ev.xselection.property);
+			return true;
+		}
+	}
+
+	return false;
+}
+
+bool RmlX11::HandleInputEvent(Rml::Context* context, Display* display, const XEvent& ev)
+{
+	switch (ev.type)
+	{
+	case ButtonPress:
+	{
+		switch (ev.xbutton.button)
+		{
+		case Button1:
+		case Button2:
+		case Button3:
+			return context->ProcessMouseButtonDown(ConvertMouseButton(ev.xbutton.button), RmlX11::GetKeyModifierState(ev.xbutton.state));
+		case Button4:
+			return context->ProcessMouseWheel(-1, RmlX11::GetKeyModifierState(ev.xbutton.state));
+		case Button5:
+			return context->ProcessMouseWheel(1, RmlX11::GetKeyModifierState(ev.xbutton.state));
+		default:
+			return true;
+		}
+	}
+	break;
+	case ButtonRelease:
+	{
+		switch (ev.xbutton.button)
+		{
+		case Button1:
+		case Button2:
+		case Button3:
+			return context->ProcessMouseButtonUp(ConvertMouseButton(ev.xbutton.button), RmlX11::GetKeyModifierState(ev.xbutton.state));
+		default:
+			return true;
+		}
+	}
+	break;
+	case MotionNotify:
+	{
+		return context->ProcessMouseMove(ev.xmotion.x, ev.xmotion.y, RmlX11::GetKeyModifierState(ev.xmotion.state));
+	}
+	break;
+	case KeyPress:
+	{
+		Rml::Input::KeyIdentifier key_identifier = RmlX11::ConvertKey(display, ev.xkey.keycode);
+		const int key_modifier_state = RmlX11::GetKeyModifierState(ev.xkey.state);
+
+		bool propagates = true;
+
+		if (key_identifier != Rml::Input::KI_UNKNOWN)
+			propagates = context->ProcessKeyDown(key_identifier, key_modifier_state);
+
+		Rml::Character character = GetCharacterCode(key_identifier, key_modifier_state);
+		if (character != Rml::Character::Null && !(key_modifier_state & Rml::Input::KM_CTRL))
+			propagates &= context->ProcessTextInput(character);
+
+		return propagates;
+	}
+	break;
+	case KeyRelease:
+	{
+		Rml::Input::KeyIdentifier key_identifier = RmlX11::ConvertKey(display, ev.xkey.keycode);
+		const int key_modifier_state = RmlX11::GetKeyModifierState(ev.xkey.state);
+
+		bool propagates = true;
+
+		if (key_identifier != Rml::Input::KI_UNKNOWN)
+			propagates = context->ProcessKeyUp(key_identifier, key_modifier_state);
+
+		return propagates;
+	}
+	break;
+	default:
+		break;
+	}
+
+	return true;
+}
+
+int RmlX11::GetKeyModifierState(int x11_state)
+{
+	int key_modifier_state = 0;
+
+	if (x11_state & ShiftMask)
+		key_modifier_state |= Rml::Input::KM_SHIFT;
+
+	if (x11_state & LockMask)
+		key_modifier_state |= Rml::Input::KM_CAPSLOCK;
+
+	if (x11_state & ControlMask)
+		key_modifier_state |= Rml::Input::KM_CTRL;
+
+	if (x11_state & Mod5Mask)
+		key_modifier_state |= Rml::Input::KM_ALT;
+
+	if (x11_state & Mod2Mask)
+		key_modifier_state |= Rml::Input::KM_NUMLOCK;
+
+	return key_modifier_state;
+}
+
+/**
+    X11 Key data used for key code conversion.
+ */
+struct XKeyData {
+#ifdef HAS_X11XKBLIB
+	bool has_xkblib = false;
+#endif // HAS_X11XKBLIB
+
+	bool initialized = false;
+	int min_keycode = 0, max_keycode = 0, keysyms_per_keycode = 0;
+	KeySym* x11_key_mapping = nullptr;
+};
+
+// Get the key data, which is initialized and filled on the first fetch.
+static const XKeyData& GetXKeyData(Display* display)
+{
+	RMLUI_ASSERT(display);
+	static XKeyData data;
+
+	if (!data.initialized)
+	{
+		data.initialized = true;
+
+#ifdef HAS_X11XKBLIB
+		int opcode_rtrn = -1;
+		int event_rtrn = -1;
+		int error_rtrn = -1;
+		int major_in_out = -1;
+		int minor_in_out = -1;
+
+		// Xkb extension may not exist in the server. This checks for its existence and initializes the extension if available.
+		data.has_xkblib = XkbQueryExtension(display, &opcode_rtrn, &event_rtrn, &error_rtrn, &major_in_out, &minor_in_out);
+
+		// if Xkb isn't available, fall back to using XGetKeyboardMapping, which may occur if RmlUi is compiled with Xkb support but the server
+		// doesn't support it. This occurs with older X11 servers or virtual framebuffers such as x11vnc server.
+		if (!data.has_xkblib)
+#endif // HAS_X11XKBLIB
+		{
+			XDisplayKeycodes(display, &data.min_keycode, &data.max_keycode);
+
+			data.x11_key_mapping = XGetKeyboardMapping(display, data.min_keycode, data.max_keycode + 1 - data.min_keycode, &data.keysyms_per_keycode);
+		}
+	}
+
+	return data;
+}
+
+Rml::Input::KeyIdentifier RmlX11::ConvertKey(Display* display, unsigned int x11_key_code)
+{
+	RMLUI_ASSERT(display);
+	const XKeyData& key_data = GetXKeyData(display);
+	
+	const int group_index = 0; // this is always 0 for our limited example
+	KeySym sym = {};
+
+#ifdef HAS_X11XKBLIB
+	if (key_data.has_xkblib)
+	{
+		sym = XkbKeycodeToKeysym(display, x11_key_code, 0, group_index);
+	}
+	else
+#endif // HAS_X11XKBLIB
+	{
+		KeySym sym_full = key_data.x11_key_mapping[(x11_key_code - key_data.min_keycode) * key_data.keysyms_per_keycode + group_index];
+
+		KeySym lower_sym, upper_sym;
+		XConvertCase(sym_full, &lower_sym, &upper_sym);
+		sym = lower_sym;
+	}
+
+	// clang-format off
+	switch (sym & 0xFF)
+	{
+	case XK_BackSpace & 0xFF:             return Rml::Input::KI_BACK;
+	case XK_Tab & 0xFF:                   return Rml::Input::KI_TAB;
+	case XK_Clear & 0xFF:                 return Rml::Input::KI_CLEAR;
+	case XK_Return & 0xFF:                return Rml::Input::KI_RETURN;
+	case XK_Pause & 0xFF:                 return Rml::Input::KI_PAUSE;
+	case XK_Scroll_Lock & 0xFF:           return Rml::Input::KI_SCROLL;
+	case XK_Escape & 0xFF:                return Rml::Input::KI_ESCAPE;
+	case XK_Delete & 0xFF:                return Rml::Input::KI_DELETE;
+
+	case XK_Kanji & 0xFF:                 return Rml::Input::KI_KANJI;
+	//	case XK_Muhenkan & 0xFF:          return Rml::Input::; /* Cancel Conversion */
+	//	case XK_Henkan_Mode & 0xFF:       return Rml::Input::; /* Start/Stop Conversion */
+	//	case XK_Henkan & 0xFF:            return Rml::Input::; /* Alias for Henkan_Mode */
+	//	case XK_Romaji & 0xFF:            return Rml::Input::; /* to Romaji */
+	//	case XK_Hiragana & 0xFF:          return Rml::Input::; /* to Hiragana */
+	//	case XK_Katakana & 0xFF:          return Rml::Input::; /* to Katakana */
+	//	case XK_Hiragana_Katakana & 0xFF: return Rml::Input::; /* Hiragana/Katakana toggle */
+	//	case XK_Zenkaku & 0xFF:           return Rml::Input::; /* to Zenkaku */
+	//	case XK_Hankaku & 0xFF:           return Rml::Input::; /* to Hankaku */
+	//	case XK_Zenkaku_Hankaku & 0xFF:   return Rml::Input::; /* Zenkaku/Hankaku toggle */
+	case XK_Touroku & 0xFF:               return Rml::Input::KI_OEM_FJ_TOUROKU;
+	//  case XK_Massyo & 0xFF:            return Rml::Input::KI_OEM_FJ_MASSHOU;
+	//	case XK_Kana_Lock & 0xFF:         return Rml::Input::; /* Kana Lock */
+	//	case XK_Kana_Shift & 0xFF:        return Rml::Input::; /* Kana Shift */
+	//	case XK_Eisu_Shift & 0xFF:        return Rml::Input::; /* Alphanumeric Shift */
+	//	case XK_Eisu_toggle & 0xFF:       return Rml::Input::; /* Alphanumeric toggle */
+
+	case XK_Home & 0xFF:                  return Rml::Input::KI_HOME;
+	case XK_Left & 0xFF:                  return Rml::Input::KI_LEFT;
+	case XK_Up & 0xFF:                    return Rml::Input::KI_UP;
+	case XK_Right & 0xFF:                 return Rml::Input::KI_RIGHT;
+	case XK_Down & 0xFF:                  return Rml::Input::KI_DOWN;
+	case XK_Prior & 0xFF:                 return Rml::Input::KI_PRIOR;
+	case XK_Next & 0xFF:                  return Rml::Input::KI_NEXT;
+	case XK_End & 0xFF:                   return Rml::Input::KI_END;
+	case XK_Begin & 0xFF:                 return Rml::Input::KI_HOME;
+
+	// case XK_Print & 0xFF:              return Rml::Input::KI_SNAPSHOT;
+	// case XK_Insert & 0xFF:             return Rml::Input::KI_INSERT;
+	case XK_Num_Lock & 0xFF:              return Rml::Input::KI_NUMLOCK;
+
+	case XK_KP_Space & 0xFF:              return Rml::Input::KI_SPACE;
+	case XK_KP_Tab & 0xFF:                return Rml::Input::KI_TAB;
+	case XK_KP_Enter & 0xFF:              return Rml::Input::KI_NUMPADENTER;
+	case XK_KP_F1 & 0xFF:                 return Rml::Input::KI_F1;
+	case XK_KP_F2 & 0xFF:                 return Rml::Input::KI_F2;
+	case XK_KP_F3 & 0xFF:                 return Rml::Input::KI_F3;
+	case XK_KP_F4 & 0xFF:                 return Rml::Input::KI_F4;
+	case XK_KP_Home & 0xFF:               return Rml::Input::KI_NUMPAD7;
+	case XK_KP_Left & 0xFF:               return Rml::Input::KI_NUMPAD4;
+	case XK_KP_Up & 0xFF:                 return Rml::Input::KI_NUMPAD8;
+	case XK_KP_Right & 0xFF:              return Rml::Input::KI_NUMPAD6;
+	case XK_KP_Down & 0xFF:               return Rml::Input::KI_NUMPAD2;
+	case XK_KP_Prior & 0xFF:              return Rml::Input::KI_NUMPAD9;
+	case XK_KP_Next & 0xFF:               return Rml::Input::KI_NUMPAD3;
+	case XK_KP_End & 0xFF:                return Rml::Input::KI_NUMPAD1;
+	case XK_KP_Begin & 0xFF:              return Rml::Input::KI_NUMPAD5;
+	case XK_KP_Insert & 0xFF:             return Rml::Input::KI_NUMPAD0;
+	case XK_KP_Delete & 0xFF:             return Rml::Input::KI_DECIMAL;
+	case XK_KP_Equal & 0xFF:              return Rml::Input::KI_OEM_NEC_EQUAL;
+	case XK_KP_Multiply & 0xFF:           return Rml::Input::KI_MULTIPLY;
+	case XK_KP_Add & 0xFF:                return Rml::Input::KI_ADD;
+	case XK_KP_Separator & 0xFF:          return Rml::Input::KI_SEPARATOR;
+	case XK_KP_Subtract & 0xFF:           return Rml::Input::KI_SUBTRACT;
+	case XK_KP_Decimal & 0xFF:            return Rml::Input::KI_DECIMAL;
+	case XK_KP_Divide & 0xFF:             return Rml::Input::KI_DIVIDE;
+
+	case XK_F1 & 0xFF:                    return Rml::Input::KI_F1;
+	case XK_F2 & 0xFF:                    return Rml::Input::KI_F2;
+	case XK_F3 & 0xFF:                    return Rml::Input::KI_F3;
+	case XK_F4 & 0xFF:                    return Rml::Input::KI_F4;
+	case XK_F5 & 0xFF:                    return Rml::Input::KI_F5;
+	case XK_F6 & 0xFF:                    return Rml::Input::KI_F6;
+	case XK_F7 & 0xFF:                    return Rml::Input::KI_F7;
+	case XK_F8 & 0xFF:                    return Rml::Input::KI_F8;
+	case XK_F9 & 0xFF:                    return Rml::Input::KI_F9;
+	case XK_F10 & 0xFF:                   return Rml::Input::KI_F10;
+	case XK_F11 & 0xFF:                   return Rml::Input::KI_F11;
+	case XK_F12 & 0xFF:                   return Rml::Input::KI_F12;
+	case XK_F13 & 0xFF:                   return Rml::Input::KI_F13;
+	case XK_F14 & 0xFF:                   return Rml::Input::KI_F14;
+	case XK_F15 & 0xFF:                   return Rml::Input::KI_F15;
+	case XK_F16 & 0xFF:                   return Rml::Input::KI_F16;
+	case XK_F17 & 0xFF:                   return Rml::Input::KI_F17;
+	case XK_F18 & 0xFF:                   return Rml::Input::KI_F18;
+	case XK_F19 & 0xFF:                   return Rml::Input::KI_F19;
+	case XK_F20 & 0xFF:                   return Rml::Input::KI_F20;
+	case XK_F21 & 0xFF:                   return Rml::Input::KI_F21;
+	case XK_F22 & 0xFF:                   return Rml::Input::KI_F22;
+	case XK_F23 & 0xFF:                   return Rml::Input::KI_F23;
+	case XK_F24 & 0xFF:                   return Rml::Input::KI_F24;
+
+	case XK_Shift_L & 0xFF:               return Rml::Input::KI_LSHIFT;
+	case XK_Shift_R & 0xFF:               return Rml::Input::KI_RSHIFT;
+	case XK_Control_L & 0xFF:             return Rml::Input::KI_LCONTROL;
+	case XK_Control_R & 0xFF:             return Rml::Input::KI_RCONTROL;
+	case XK_Caps_Lock & 0xFF:             return Rml::Input::KI_CAPITAL;
+
+	case XK_Alt_L & 0xFF:                 return Rml::Input::KI_LMENU;
+	case XK_Alt_R & 0xFF:                 return Rml::Input::KI_RMENU;
+
+	case XK_space & 0xFF:                 return Rml::Input::KI_SPACE;
+	case XK_apostrophe & 0xFF:            return Rml::Input::KI_OEM_7;
+	case XK_comma & 0xFF:                 return Rml::Input::KI_OEM_COMMA;
+	case XK_minus & 0xFF:                 return Rml::Input::KI_OEM_MINUS;
+	case XK_period & 0xFF:                return Rml::Input::KI_OEM_PERIOD;
+	case XK_slash & 0xFF:                 return Rml::Input::KI_OEM_2;
+	case XK_0 & 0xFF:                     return Rml::Input::KI_0;
+	case XK_1 & 0xFF:                     return Rml::Input::KI_1;
+	case XK_2 & 0xFF:                     return Rml::Input::KI_2;
+	case XK_3 & 0xFF:                     return Rml::Input::KI_3;
+	case XK_4 & 0xFF:                     return Rml::Input::KI_4;
+	case XK_5 & 0xFF:                     return Rml::Input::KI_5;
+	case XK_6 & 0xFF:                     return Rml::Input::KI_6;
+	case XK_7 & 0xFF:                     return Rml::Input::KI_7;
+	case XK_8 & 0xFF:                     return Rml::Input::KI_8;
+	case XK_9 & 0xFF:                     return Rml::Input::KI_9;
+	case XK_semicolon & 0xFF:             return Rml::Input::KI_OEM_1;
+	case XK_equal & 0xFF:                 return Rml::Input::KI_OEM_PLUS;
+	case XK_bracketleft & 0xFF:           return Rml::Input::KI_OEM_4;
+	case XK_backslash & 0xFF:             return Rml::Input::KI_OEM_5;
+	case XK_bracketright & 0xFF:          return Rml::Input::KI_OEM_6;
+	case XK_grave & 0xFF:                 return Rml::Input::KI_OEM_3;
+	case XK_a & 0xFF:                     return Rml::Input::KI_A;
+	case XK_b & 0xFF:                     return Rml::Input::KI_B;
+	case XK_c & 0xFF:                     return Rml::Input::KI_C;
+	case XK_d & 0xFF:                     return Rml::Input::KI_D;
+	case XK_e & 0xFF:                     return Rml::Input::KI_E;
+	case XK_f & 0xFF:                     return Rml::Input::KI_F;
+	case XK_g & 0xFF:                     return Rml::Input::KI_G;
+	case XK_h & 0xFF:                     return Rml::Input::KI_H;
+	case XK_i & 0xFF:                     return Rml::Input::KI_I;
+	case XK_j & 0xFF:                     return Rml::Input::KI_J;
+	case XK_k & 0xFF:                     return Rml::Input::KI_K;
+	case XK_l & 0xFF:                     return Rml::Input::KI_L;
+	case XK_m & 0xFF:                     return Rml::Input::KI_M;
+	case XK_n & 0xFF:                     return Rml::Input::KI_N;
+	case XK_o & 0xFF:                     return Rml::Input::KI_O;
+	case XK_p & 0xFF:                     return Rml::Input::KI_P;
+	case XK_q & 0xFF:                     return Rml::Input::KI_Q;
+	case XK_r & 0xFF:                     return Rml::Input::KI_R;
+	case XK_s & 0xFF:                     return Rml::Input::KI_S;
+	case XK_t & 0xFF:                     return Rml::Input::KI_T;
+	case XK_u & 0xFF:                     return Rml::Input::KI_U;
+	case XK_v & 0xFF:                     return Rml::Input::KI_V;
+	case XK_w & 0xFF:                     return Rml::Input::KI_W;
+	case XK_x & 0xFF:                     return Rml::Input::KI_X;
+	case XK_y & 0xFF:                     return Rml::Input::KI_Y;
+	case XK_z & 0xFF:                     return Rml::Input::KI_Z;
+	default: break;
+	}
+	// clang-format on
+
+	return Rml::Input::KI_UNKNOWN;
+}
+
+int RmlX11::ConvertMouseButton(unsigned int x11_mouse_button)
+{
+	switch (x11_mouse_button)
+	{
+	case Button1:
+		return 0;
+	case Button2:
+		return 2;
+	case Button3:
+		return 1;
+	default:
+		break;
+	}
+	return 0;
+}
+
+/**
+    This map contains 4 different mappings from key identifiers to character codes. Each entry represents a different
+    combination of shift and capslock state.
+ */
+
+static char ascii_map[4][51] = {
+	// shift off and capslock off
+	{0, ' ', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q',
+		'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', ';', '=', ',', '-', '.', '/', '`', '[', '\\', ']', '\'', 0, 0},
+	// shift on and capslock off
+	{0, ' ', ')', '!', '@', '#', '$', '%', '^', '&', '*', '(', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q',
+		'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', ':', '+', '<', '_', '>', '?', '~', '{', '|', '}', '"', 0, 0},
+	// shift on and capslock on
+	{0, ' ', ')', '!', '@', '#', '$', '%', '^', '&', '*', '(', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q',
+		'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', ':', '+', '<', '_', '>', '?', '~', '{', '|', '}', '"', 0, 0},
+	// shift off and capslock on
+	{0, ' ', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q',
+		'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', ';', '=', ',', '-', '.', '/', '`', '[', '\\', ']', '\'', 0, 0}};
+
+static char keypad_map[2][18] = {{'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '\n', '*', '+', 0, '-', '.', '/', '='},
+	{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, '\n', '*', '+', 0, '-', 0, '/', '='}};
+
+// Returns the character code for a key identifer / key modifier combination.
+static Rml::Character GetCharacterCode(Rml::Input::KeyIdentifier key_identifier, int key_modifier_state)
+{
+	using Rml::Character;
+
+	// Check if we have a keycode capable of generating characters on the main keyboard (ie, not on the numeric
+	// keypad; that is dealt with below).
+	if (key_identifier <= Rml::Input::KI_OEM_102)
+	{
+		// Get modifier states
+		bool shift = (key_modifier_state & Rml::Input::KM_SHIFT) > 0;
+		bool capslock = (key_modifier_state & Rml::Input::KM_CAPSLOCK) > 0;
+
+		// Return character code based on identifier and modifiers
+		if (shift && !capslock)
+			return (Character)ascii_map[1][key_identifier];
+
+		if (shift && capslock)
+			return (Character)ascii_map[2][key_identifier];
+
+		if (!shift && capslock)
+			return (Character)ascii_map[3][key_identifier];
+
+		return (Character)ascii_map[0][key_identifier];
+	}
+
+	// Check if we have a keycode from the numeric keypad.
+	else if (key_identifier <= Rml::Input::KI_OEM_NEC_EQUAL)
+	{
+		if (key_modifier_state & Rml::Input::KM_NUMLOCK)
+			return (Character)keypad_map[0][key_identifier - Rml::Input::KI_NUMPAD0];
+		else
+			return (Character)keypad_map[1][key_identifier - Rml::Input::KI_NUMPAD0];
+	}
+
+	else if (key_identifier == Rml::Input::KI_RETURN)
+		return (Character)'\n';
+
+	return Character::Null;
+}

+ 106 - 0
Backends/RmlUi_Platform_X11.h

@@ -0,0 +1,106 @@
+/*
+ * This source file is part of RmlUi, the HTML/CSS Interface Middleware
+ *
+ * For the latest information, see http://github.com/mikke89/RmlUi
+ *
+ * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd
+ * Copyright (c) 2019 The RmlUi Team, and contributors
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ */
+
+#ifndef RMLUI_BACKENDS_PLATFORM_X11_H
+#define RMLUI_BACKENDS_PLATFORM_X11_H
+
+#include "RmlUi_Include_Xlib.h"
+#include <RmlUi/Core/Input.h>
+#include <RmlUi/Core/SystemInterface.h>
+#include <RmlUi/Core/Types.h>
+#include <X11/Xutil.h>
+
+class SystemInterface_X11 : public Rml::SystemInterface {
+public:
+	SystemInterface_X11(Display* display);
+
+	// Optionally, provide or change the window to be used for setting the mouse cursors and clipboard text.
+	void SetWindow(Window window);
+
+	// Handle selection request events.
+	// @return True if the event is still propagating, false if it was handled here.
+	bool HandleSelectionRequest(const XEvent& ev);
+
+	// -- Inherited from Rml::SystemInterface  --
+
+	double GetElapsedTime() override;
+
+	void SetMouseCursor(const Rml::String& cursor_name) override;
+
+	void SetClipboardText(const Rml::String& text) override;
+	void GetClipboardText(Rml::String& text) override;
+
+private:
+	void XCopy(const Rml::String& clipboard_data, const XEvent& event);
+	bool XPaste(Atom target_atom, Rml::String& clipboard_data);
+
+	Display* display = nullptr;
+	Window window = 0;
+	timeval start_time;
+
+	Cursor cursor_default = 0;
+	Cursor cursor_move = 0;
+	Cursor cursor_pointer = 0;
+	Cursor cursor_resize = 0;
+	Cursor cursor_cross = 0;
+	Cursor cursor_text = 0;
+	Cursor cursor_unavailable = 0;
+
+	// -- Clipboard
+	Rml::String clipboard_text;
+	Atom XA_atom = 4;
+	Atom XA_STRING_atom = 31;
+	Atom UTF8_atom;
+	Atom CLIPBOARD_atom;
+	Atom XSEL_DATA_atom;
+	Atom TARGETS_atom;
+	Atom TEXT_atom;
+};
+
+/**
+    Optional helper functions for the X11 plaform.
+ */
+namespace RmlX11 {
+
+// Applies input on the context based on the given SFML event.
+// @return True if the event is still propagating, false if it was handled by the context.
+bool HandleInputEvent(Rml::Context* context, Display* display, const XEvent& ev);
+
+// Converts the X11 key code to RmlUi key.
+// @note The display must be passed here as it needs to query the connected X server display for information about its install keymap abilities.
+Rml::Input::KeyIdentifier ConvertKey(Display* display, unsigned int x11_key_code);
+
+// Converts the X11 mouse button to RmlUi mouse button.
+int ConvertMouseButton(unsigned int x11_mouse_button);
+
+// Converts the X11 key modifier to RmlUi key modifier.
+int GetKeyModifierState(int x11_state);
+
+} // namespace RmlX11
+
+#endif

+ 274 - 0
Backends/RmlUi_Renderer_GL2.cpp

@@ -0,0 +1,274 @@
+/*
+ * This source file is part of RmlUi, the HTML/CSS Interface Middleware
+ *
+ * For the latest information, see http://github.com/mikke89/RmlUi
+ *
+ * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd
+ * Copyright (c) 2019 The RmlUi Team, and contributors
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ */
+
+#include "RmlUi_Renderer_GL2.h"
+#include <RmlUi/Core/Core.h>
+#include <RmlUi/Core/FileInterface.h>
+#include <RmlUi/Core/Log.h>
+#include <RmlUi/Core/Platform.h>
+#include <string.h>
+
+#if defined RMLUI_PLATFORM_WIN32
+	#include "RmlUi_Include_Windows.h"
+	#include <gl/Gl.h>
+	#include <gl/Glu.h>
+#elif defined RMLUI_PLATFORM_MACOSX
+	#include <AGL/agl.h>
+	#include <OpenGL/gl.h>
+	#include <OpenGL/glext.h>
+	#include <OpenGL/glu.h>
+#elif defined RMLUI_PLATFORM_UNIX
+	#include "RmlUi_Include_Xlib.h"
+	#include <GL/gl.h>
+	#include <GL/glext.h>
+	#include <GL/glu.h>
+	#include <GL/glx.h>
+#endif
+
+#define GL_CLAMP_TO_EDGE 0x812F
+
+RenderInterface_GL2::RenderInterface_GL2() {}
+
+void RenderInterface_GL2::SetViewport(int in_viewport_width, int in_viewport_height)
+{
+	viewport_width = in_viewport_width;
+	viewport_height = in_viewport_height;
+}
+
+void RenderInterface_GL2::BeginFrame()
+{
+	RMLUI_ASSERT(viewport_width > 0 && viewport_height > 0);
+	glViewport(0, 0, viewport_width, viewport_height);
+
+	glEnableClientState(GL_VERTEX_ARRAY);
+	glEnableClientState(GL_COLOR_ARRAY);
+	glDisableClientState(GL_TEXTURE_COORD_ARRAY);
+
+	glEnable(GL_BLEND);
+	glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+
+	Rml::Matrix4f projection = Rml::Matrix4f::ProjectOrtho(0, (float)viewport_width, (float)viewport_height, 0, -10000, 10000);
+	glMatrixMode(GL_PROJECTION);
+	glLoadMatrixf(projection.data());
+	glMatrixMode(GL_TEXTURE);
+	glLoadIdentity();
+	glMatrixMode(GL_MODELVIEW);
+	glLoadIdentity();
+}
+
+void RenderInterface_GL2::EndFrame() {}
+
+void RenderInterface_GL2::Clear()
+{
+	glClearStencil(0);
+	glClearColor(0, 0, 0, 1);
+	glClear(GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
+}
+
+void RenderInterface_GL2::RenderGeometry(Rml::Vertex* vertices, int /*num_vertices*/, int* indices, int num_indices, const Rml::TextureHandle texture,
+	const Rml::Vector2f& translation)
+{
+	glPushMatrix();
+	glTranslatef(translation.x, translation.y, 0);
+
+	glVertexPointer(2, GL_FLOAT, sizeof(Rml::Vertex), &vertices[0].position);
+	glColorPointer(4, GL_UNSIGNED_BYTE, sizeof(Rml::Vertex), &vertices[0].colour);
+
+	if (!texture)
+	{
+		glDisable(GL_TEXTURE_2D);
+		glDisableClientState(GL_TEXTURE_COORD_ARRAY);
+	}
+	else
+	{
+		glEnable(GL_TEXTURE_2D);
+
+		if (texture != TextureEnableWithoutBinding)
+			glBindTexture(GL_TEXTURE_2D, (GLuint)texture);
+
+		glEnableClientState(GL_TEXTURE_COORD_ARRAY);
+		glTexCoordPointer(2, GL_FLOAT, sizeof(Rml::Vertex), &vertices[0].tex_coord);
+	}
+
+	glDrawElements(GL_TRIANGLES, num_indices, GL_UNSIGNED_INT, indices);
+
+	glPopMatrix();
+}
+
+void RenderInterface_GL2::EnableScissorRegion(bool enable)
+{
+	if (enable)
+		glEnable(GL_SCISSOR_TEST);
+	else
+		glDisable(GL_SCISSOR_TEST);
+}
+
+void RenderInterface_GL2::SetScissorRegion(int x, int y, int width, int height)
+{
+	glScissor(x, viewport_height - (y + height), width, height);
+}
+
+// Set to byte packing, or the compiler will expand our struct, which means it won't read correctly from file
+#pragma pack(1)
+struct TGAHeader {
+	char idLength;
+	char colourMapType;
+	char dataType;
+	short int colourMapOrigin;
+	short int colourMapLength;
+	char colourMapDepth;
+	short int xOrigin;
+	short int yOrigin;
+	short int width;
+	short int height;
+	char bitsPerPixel;
+	char imageDescriptor;
+};
+// Restore packing
+#pragma pack()
+
+bool RenderInterface_GL2::LoadTexture(Rml::TextureHandle& texture_handle, Rml::Vector2i& texture_dimensions, const Rml::String& source)
+{
+	Rml::FileInterface* file_interface = Rml::GetFileInterface();
+	Rml::FileHandle file_handle = file_interface->Open(source);
+	if (!file_handle)
+	{
+		return false;
+	}
+
+	file_interface->Seek(file_handle, 0, SEEK_END);
+	size_t buffer_size = file_interface->Tell(file_handle);
+	file_interface->Seek(file_handle, 0, SEEK_SET);
+
+	if (buffer_size <= sizeof(TGAHeader))
+	{
+		Rml::Log::Message(Rml::Log::LT_ERROR, "Texture file size is smaller than TGAHeader, file is not a valid TGA image.");
+		file_interface->Close(file_handle);
+		return false;
+	}
+
+	char* buffer = new char[buffer_size];
+	file_interface->Read(buffer, buffer_size, file_handle);
+	file_interface->Close(file_handle);
+
+	TGAHeader header;
+	memcpy(&header, buffer, sizeof(TGAHeader));
+
+	int color_mode = header.bitsPerPixel / 8;
+	int image_size = header.width * header.height * 4; // We always make 32bit textures
+
+	if (header.dataType != 2)
+	{
+		Rml::Log::Message(Rml::Log::LT_ERROR, "Only 24/32bit uncompressed TGAs are supported.");
+		delete[] buffer;
+		return false;
+	}
+
+	// Ensure we have at least 3 colors
+	if (color_mode < 3)
+	{
+		Rml::Log::Message(Rml::Log::LT_ERROR, "Only 24 and 32bit textures are supported.");
+		delete[] buffer;
+		return false;
+	}
+
+	const char* image_src = buffer + sizeof(TGAHeader);
+	unsigned char* image_dest = new unsigned char[image_size];
+
+	// Targa is BGR, swap to RGB and flip Y axis
+	for (long y = 0; y < header.height; y++)
+	{
+		long read_index = y * header.width * color_mode;
+		long write_index = ((header.imageDescriptor & 32) != 0) ? read_index : (header.height - y - 1) * header.width * color_mode;
+		for (long x = 0; x < header.width; x++)
+		{
+			image_dest[write_index] = image_src[read_index + 2];
+			image_dest[write_index + 1] = image_src[read_index + 1];
+			image_dest[write_index + 2] = image_src[read_index];
+			if (color_mode == 4)
+				image_dest[write_index + 3] = image_src[read_index + 3];
+			else
+				image_dest[write_index + 3] = 255;
+
+			write_index += 4;
+			read_index += color_mode;
+		}
+	}
+
+	texture_dimensions.x = header.width;
+	texture_dimensions.y = header.height;
+
+	bool success = GenerateTexture(texture_handle, image_dest, texture_dimensions);
+
+	delete[] image_dest;
+	delete[] buffer;
+
+	return success;
+}
+
+bool RenderInterface_GL2::GenerateTexture(Rml::TextureHandle& texture_handle, const Rml::byte* source, const Rml::Vector2i& source_dimensions)
+{
+	GLuint texture_id = 0;
+	glGenTextures(1, &texture_id);
+	if (texture_id == 0)
+	{
+		Rml::Log::Message(Rml::Log::LT_ERROR, "Failed to generate texture.");
+		return false;
+	}
+
+	glBindTexture(GL_TEXTURE_2D, texture_id);
+
+	glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, source_dimensions.x, source_dimensions.y, 0, GL_RGBA, GL_UNSIGNED_BYTE, source);
+	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+
+	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+
+	texture_handle = (Rml::TextureHandle)texture_id;
+
+	return true;
+}
+
+void RenderInterface_GL2::ReleaseTexture(Rml::TextureHandle texture_handle)
+{
+	glDeleteTextures(1, (GLuint*)&texture_handle);
+}
+
+void RenderInterface_GL2::SetTransform(const Rml::Matrix4f* transform)
+{
+	if (transform)
+	{
+		if (std::is_same<Rml::Matrix4f, Rml::ColumnMajorMatrix4f>::value)
+			glLoadMatrixf(transform->data());
+		else if (std::is_same<Rml::Matrix4f, Rml::RowMajorMatrix4f>::value)
+			glLoadMatrixf(transform->Transpose().data());
+	}
+	else
+		glLoadIdentity();
+}

+ 70 - 68
Samples/basic/sdl2_sdlrenderer/src/RenderInterfaceSDL2.h → Backends/RmlUi_Renderer_GL2.h

@@ -1,68 +1,70 @@
-/*
- * This source file is part of RmlUi, the HTML/CSS Interface Middleware
- *
- * For the latest information, see http://github.com/mikke89/RmlUi
- *
- * Copyright (c) 2008-2010 Nuno Silva
- * Copyright (c) 2019 The RmlUi Team, and contributors
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- * 
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- *
- */
-#ifndef RENDERINTERFACESDL2_H
-#define RENDERINTERFACESDL2_H
-
-#include <RmlUi/Core/RenderInterface.h>
-
-#include <SDL.h>
-
-#if !(SDL_VIDEO_RENDER_OGL)
-    #error "Only the opengl sdl backend is supported."
-#endif
-
-
-class RmlUiSDL2Renderer : public Rml::RenderInterface
-{
-public:
-	RmlUiSDL2Renderer(SDL_Renderer* renderer, SDL_Window* screen);
-
-	/// Called by RmlUi when it wants to render geometry that it does not wish to optimise.
-	void RenderGeometry(Rml::Vertex* vertices, int num_vertices, int* indices, int num_indices, Rml::TextureHandle texture, const Rml::Vector2f& translation) override;
-
-	/// Called by RmlUi when it wants to enable or disable scissoring to clip content.
-	void EnableScissorRegion(bool enable) override;
-	/// Called by RmlUi when it wants to change the scissor region.
-	void SetScissorRegion(int x, int y, int width, int height) override;
-
-	/// Called by RmlUi when a texture is required by the library.
-	bool LoadTexture(Rml::TextureHandle& texture_handle, Rml::Vector2i& texture_dimensions, const Rml::String& source) override;
-	/// Called by RmlUi when a texture is required to be built from an internally-generated sequence of pixels.
-	bool GenerateTexture(Rml::TextureHandle& texture_handle, const Rml::byte* source, const Rml::Vector2i& source_dimensions) override;
-	/// Called by RmlUi when a loaded texture is no longer required.
-	void ReleaseTexture(Rml::TextureHandle texture_handle) override;
-
-private:
-    SDL_Renderer* mRenderer;
-    int mRenderer_w;
-    int mRenderer_h;
-    SDL_Window* mScreen;
-    SDL_Rect mRectScisor;
-};
-
-#endif
+/*
+ * This source file is part of RmlUi, the HTML/CSS Interface Middleware
+ *
+ * For the latest information, see http://github.com/mikke89/RmlUi
+ *
+ * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd
+ * Copyright (c) 2019 The RmlUi Team, and contributors
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ */
+
+#ifndef RMLUI_BACKENDS_RENDERER_GL2_H
+#define RMLUI_BACKENDS_RENDERER_GL2_H
+
+#include <RmlUi/Core/RenderInterface.h>
+
+class RenderInterface_GL2 : public Rml::RenderInterface {
+public:
+	RenderInterface_GL2();
+
+	// The viewport should be updated whenever the window size changes.
+	void SetViewport(int viewport_width, int viewport_height);
+
+	// Sets up OpenGL states for taking rendering commands from RmlUi.
+	void BeginFrame();
+	void EndFrame();
+
+	// Optional, can be used to clear the framebuffer.
+	void Clear();
+
+	// -- Inherited from Rml::RenderInterface --
+
+	void RenderGeometry(Rml::Vertex* vertices, int num_vertices, int* indices, int num_indices, Rml::TextureHandle texture,
+		const Rml::Vector2f& translation) override;
+
+	void EnableScissorRegion(bool enable) override;
+	void SetScissorRegion(int x, int y, int width, int height) override;
+
+	bool LoadTexture(Rml::TextureHandle& texture_handle, Rml::Vector2i& texture_dimensions, const Rml::String& source) override;
+	bool GenerateTexture(Rml::TextureHandle& texture_handle, const Rml::byte* source, const Rml::Vector2i& source_dimensions) override;
+	void ReleaseTexture(Rml::TextureHandle texture_handle) override;
+
+	void SetTransform(const Rml::Matrix4f* transform) override;
+
+	// Can be passed to RenderGeometry() to enable texture rendering without changing the bound texture.
+	static const Rml::TextureHandle TextureEnableWithoutBinding = Rml::TextureHandle(-1);
+
+private:
+	int viewport_width = 0;
+	int viewport_height = 0;
+};
+
+#endif

+ 700 - 0
Backends/RmlUi_Renderer_GL3.cpp

@@ -0,0 +1,700 @@
+/*
+ * This source file is part of RmlUi, the HTML/CSS Interface Middleware
+ *
+ * For the latest information, see http://github.com/mikke89/RmlUi
+ *
+ * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd
+ * Copyright (c) 2019 The RmlUi Team, and contributors
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ */
+
+#include "RmlUi_Renderer_GL3.h"
+#include <RmlUi/Core/Core.h>
+#include <RmlUi/Core/FileInterface.h>
+#include <RmlUi/Core/Log.h>
+#include <RmlUi/Core/Platform.h>
+#include <string.h>
+
+#if defined(RMLUI_PLATFORM_WIN32) && !defined(__MINGW32__)
+	// function call missing argument list
+	#pragma warning(disable : 4551)
+	// unreferenced local function has been removed
+	#pragma warning(disable : 4505)
+#endif
+
+#if defined RMLUI_PLATFORM_EMSCRIPTEN
+	#define RMLUI_SHADER_HEADER "#version 300 es\nprecision highp float;\n"
+	#include <GLES3/gl3.h>
+#else
+	#define RMLUI_SHADER_HEADER "#version 330\n"
+	#define GLAD_GL_IMPLEMENTATION
+	#include "RmlUi_Include_GL3.h"
+#endif
+
+static const char* shader_main_vertex = RMLUI_SHADER_HEADER R"(
+uniform vec2 _translate;
+uniform mat4 _transform;
+
+in vec2 inPosition;
+in vec4 inColor0;
+in vec2 inTexCoord0;
+
+out vec2 fragTexCoord;
+out vec4 fragColor;
+
+void main() {
+	fragTexCoord = inTexCoord0;
+	fragColor = inColor0;
+
+	vec2 translatedPos = inPosition + _translate.xy;
+	vec4 outPos = _transform * vec4(translatedPos, 0, 1);
+
+    gl_Position = outPos;
+}
+)";
+
+static const char* shader_main_fragment_texture = RMLUI_SHADER_HEADER R"(
+uniform sampler2D _tex;
+in vec2 fragTexCoord;
+in vec4 fragColor;
+
+out vec4 finalColor;
+
+void main() {
+	vec4 texColor = texture(_tex, fragTexCoord);
+	finalColor = fragColor * texColor;
+}
+)";
+static const char* shader_main_fragment_color = RMLUI_SHADER_HEADER R"(
+in vec2 fragTexCoord;
+in vec4 fragColor;
+
+out vec4 finalColor;
+
+void main() {
+	finalColor = fragColor;
+}
+)";
+
+namespace Gfx {
+
+enum class ProgramUniform { Translate, Transform, Tex, Count };
+static const char* const program_uniform_names[(size_t)ProgramUniform::Count] = {"_translate", "_transform", "_tex"};
+
+enum class VertexAttribute { Position, Color0, TexCoord0, Count };
+static const char* const vertex_attribute_names[(size_t)VertexAttribute::Count] = {"inPosition", "inColor0", "inTexCoord0"};
+
+struct CompiledGeometryData {
+	GLuint texture;
+	GLuint vao;
+	GLuint vbo;
+	GLuint ibo;
+	GLsizei draw_count;
+};
+
+struct ProgramData {
+	GLuint id;
+	GLint uniform_locations[(size_t)ProgramUniform::Count];
+};
+
+struct ShadersData {
+	ProgramData program_color;
+	ProgramData program_texture;
+	GLuint shader_main_vertex;
+	GLuint shader_main_fragment_color;
+	GLuint shader_main_fragment_texture;
+};
+
+static void CheckGLError(const char* operation_name)
+{
+#ifdef RMLUI_DEBUG
+	GLenum error_code = glGetError();
+	if (error_code != GL_NO_ERROR)
+	{
+		static const Rml::Pair<GLenum, const char*> error_names[] = {{GL_INVALID_ENUM, "GL_INVALID_ENUM"}, {GL_INVALID_VALUE, "GL_INVALID_VALUE"},
+			{GL_INVALID_OPERATION, "GL_INVALID_OPERATION"}, {GL_OUT_OF_MEMORY, "GL_OUT_OF_MEMORY"}};
+		const char* error_str = "''";
+		for (auto& err : error_names)
+		{
+			if (err.first == error_code)
+			{
+				error_str = err.second;
+				break;
+			}
+		}
+		Rml::Log::Message(Rml::Log::LT_ERROR, "OpenGL error during %s. Error code 0x%x (%s).", operation_name, error_code, error_str);
+	}
+#endif
+	(void)operation_name;
+}
+
+// Create the shader, 'shader_type' is either GL_VERTEX_SHADER or GL_FRAGMENT_SHADER.
+static GLuint CreateShader(GLenum shader_type, const char* code_string)
+{
+	GLuint id = glCreateShader(shader_type);
+
+	glShaderSource(id, 1, (const GLchar**)&code_string, NULL);
+	glCompileShader(id);
+
+	GLint status = 0;
+	glGetShaderiv(id, GL_COMPILE_STATUS, &status);
+	if (status == GL_FALSE)
+	{
+		GLint info_log_length = 0;
+		glGetShaderiv(id, GL_INFO_LOG_LENGTH, &info_log_length);
+		char* info_log_string = new char[info_log_length + 1];
+		glGetShaderInfoLog(id, info_log_length, NULL, info_log_string);
+
+		Rml::Log::Message(Rml::Log::LT_ERROR, "Compile failure in OpenGL shader: %s", info_log_string);
+		delete[] info_log_string;
+		glDeleteShader(id);
+		return 0;
+	}
+
+	CheckGLError("CreateShader");
+
+	return id;
+}
+
+static void BindAttribLocations(GLuint program)
+{
+	for (GLuint i = 0; i < (GLuint)VertexAttribute::Count; i++)
+	{
+		glBindAttribLocation(program, i, vertex_attribute_names[i]);
+	}
+	CheckGLError("BindAttribLocations");
+}
+
+static bool CreateProgram(GLuint vertex_shader, GLuint fragment_shader, ProgramData& out_program)
+{
+	GLuint id = glCreateProgram();
+	RMLUI_ASSERT(id);
+
+	BindAttribLocations(id);
+
+	glAttachShader(id, vertex_shader);
+	glAttachShader(id, fragment_shader);
+
+	glLinkProgram(id);
+
+	glDetachShader(id, vertex_shader);
+	glDetachShader(id, fragment_shader);
+
+	GLint status = 0;
+	glGetProgramiv(id, GL_LINK_STATUS, &status);
+	if (status == GL_FALSE)
+	{
+		GLint info_log_length = 0;
+		glGetProgramiv(id, GL_INFO_LOG_LENGTH, &info_log_length);
+		char* info_log_string = new char[info_log_length + 1];
+		glGetProgramInfoLog(id, info_log_length, NULL, info_log_string);
+
+		Rml::Log::Message(Rml::Log::LT_ERROR, "OpenGL program linking failure: %s", info_log_string);
+		delete[] info_log_string;
+		glDeleteProgram(id);
+		return false;
+	}
+
+	out_program = {};
+	out_program.id = id;
+
+	// Make a lookup table for the uniform locations.
+	GLint num_active_uniforms = 0;
+	glGetProgramiv(id, GL_ACTIVE_UNIFORMS, &num_active_uniforms);
+
+	constexpr size_t name_size = 64;
+	GLchar name_buf[name_size] = "";
+	for (int unif = 0; unif < num_active_uniforms; ++unif)
+	{
+		GLint array_size = 0;
+		GLenum type = 0;
+		GLsizei actual_length = 0;
+		glGetActiveUniform(id, unif, name_size, &actual_length, &array_size, &type, name_buf);
+		GLint location = glGetUniformLocation(id, name_buf);
+
+		// See if we have the name in our pre-defined name list.
+		ProgramUniform program_uniform = ProgramUniform::Count;
+		for (int i = 0; i < (int)ProgramUniform::Count; i++)
+		{
+			const char* uniform_name = program_uniform_names[i];
+			if (strcmp(name_buf, uniform_name) == 0)
+			{
+				program_uniform = (ProgramUniform)i;
+				break;
+			}
+		}
+
+		if ((size_t)program_uniform < (size_t)ProgramUniform::Count)
+		{
+			out_program.uniform_locations[(size_t)program_uniform] = location;
+		}
+		else
+		{
+			Rml::Log::Message(Rml::Log::LT_ERROR, "OpenGL program uses unknown uniform '%s'.", name_buf);
+			return false;
+		}
+	}
+
+	CheckGLError("CreateProgram");
+
+	return true;
+}
+
+static bool CreateShaders(ShadersData& out_shaders)
+{
+	out_shaders = {};
+	GLuint& main_vertex = out_shaders.shader_main_vertex;
+	GLuint& main_fragment_color = out_shaders.shader_main_fragment_color;
+	GLuint& main_fragment_texture = out_shaders.shader_main_fragment_texture;
+
+	main_vertex = CreateShader(GL_VERTEX_SHADER, shader_main_vertex);
+	if (!main_vertex)
+	{
+		Rml::Log::Message(Rml::Log::LT_ERROR, "Could not create OpenGL shader: 'shader_main_vertex'.");
+		return false;
+	}
+	main_fragment_color = CreateShader(GL_FRAGMENT_SHADER, shader_main_fragment_color);
+	if (!main_fragment_color)
+	{
+		Rml::Log::Message(Rml::Log::LT_ERROR, "Could not create OpenGL shader: 'shader_main_fragment_color'.");
+		return false;
+	}
+	main_fragment_texture = CreateShader(GL_FRAGMENT_SHADER, shader_main_fragment_texture);
+	if (!main_fragment_texture)
+	{
+		Rml::Log::Message(Rml::Log::LT_ERROR, "Could not create OpenGL shader: 'shader_main_fragment_texture'.");
+		return false;
+	}
+
+	if (!CreateProgram(main_vertex, main_fragment_color, out_shaders.program_color))
+	{
+		Rml::Log::Message(Rml::Log::LT_ERROR, "Could not create OpenGL program: 'program_color'.");
+		return false;
+	}
+	if (!CreateProgram(main_vertex, main_fragment_texture, out_shaders.program_texture))
+	{
+		Rml::Log::Message(Rml::Log::LT_ERROR, "Could not create OpenGL program: 'program_texture'.");
+		return false;
+	}
+
+	return true;
+}
+
+static void DestroyShaders(ShadersData& shaders)
+{
+	glDeleteProgram(shaders.program_color.id);
+	glDeleteProgram(shaders.program_texture.id);
+
+	glDeleteShader(shaders.shader_main_vertex);
+	glDeleteShader(shaders.shader_main_fragment_color);
+	glDeleteShader(shaders.shader_main_fragment_texture);
+
+	shaders = {};
+}
+
+} // namespace Gfx
+
+RenderInterface_GL3::RenderInterface_GL3()
+{
+	shaders = Rml::MakeUnique<Gfx::ShadersData>();
+
+	if (!Gfx::CreateShaders(*shaders))
+		shaders.reset();
+}
+
+RenderInterface_GL3::~RenderInterface_GL3()
+{
+	if (shaders)
+		Gfx::DestroyShaders(*shaders);
+}
+
+void RenderInterface_GL3::SetViewport(int width, int height)
+{
+	viewport_width = width;
+	viewport_height = height;
+}
+
+void RenderInterface_GL3::BeginFrame()
+{
+	RMLUI_ASSERT(viewport_width > 0 && viewport_height > 0);
+	glViewport(0, 0, viewport_width, viewport_height);
+
+	glClearStencil(0);
+	glClearColor(0, 0, 0, 1);
+
+	glDisable(GL_CULL_FACE);
+
+	glEnable(GL_STENCIL_TEST);
+	glStencilFunc(GL_ALWAYS, 1, GLuint(-1));
+	glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
+
+	glEnable(GL_BLEND);
+	glBlendEquation(GL_FUNC_ADD);
+	glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+
+	projection = Rml::Matrix4f::ProjectOrtho(0, (float)viewport_width, (float)viewport_height, 0, -10000, 10000);
+
+	SetTransform(nullptr);
+}
+
+void RenderInterface_GL3::EndFrame() {}
+
+void RenderInterface_GL3::Clear()
+{
+	glClearStencil(0);
+	glClearColor(0, 0, 0, 1);
+	glClear(GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
+}
+
+void RenderInterface_GL3::RenderGeometry(Rml::Vertex* vertices, int num_vertices, int* indices, int num_indices, const Rml::TextureHandle texture,
+	const Rml::Vector2f& translation)
+{
+	Rml::CompiledGeometryHandle geometry = CompileGeometry(vertices, num_vertices, indices, num_indices, texture);
+
+	if (geometry)
+	{
+		RenderCompiledGeometry(geometry, translation);
+		ReleaseCompiledGeometry(geometry);
+	}
+}
+
+Rml::CompiledGeometryHandle RenderInterface_GL3::CompileGeometry(Rml::Vertex* vertices, int num_vertices, int* indices, int num_indices,
+	Rml::TextureHandle texture)
+{
+	constexpr GLenum draw_usage = GL_STATIC_DRAW;
+
+	GLuint vao = 0;
+	GLuint vbo = 0;
+	GLuint ibo = 0;
+
+	glGenVertexArrays(1, &vao);
+	glGenBuffers(1, &vbo);
+	glGenBuffers(1, &ibo);
+	glBindVertexArray(vao);
+
+	glBindBuffer(GL_ARRAY_BUFFER, vbo);
+	glBufferData(GL_ARRAY_BUFFER, sizeof(Rml::Vertex) * num_vertices, (const void*)vertices, draw_usage);
+
+	glEnableVertexAttribArray((GLuint)Gfx::VertexAttribute::Position);
+	glVertexAttribPointer((GLuint)Gfx::VertexAttribute::Position, 2, GL_FLOAT, GL_FALSE, sizeof(Rml::Vertex),
+		(const GLvoid*)(offsetof(Rml::Vertex, position)));
+
+	glEnableVertexAttribArray((GLuint)Gfx::VertexAttribute::Color0);
+	glVertexAttribPointer((GLuint)Gfx::VertexAttribute::Color0, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(Rml::Vertex),
+		(const GLvoid*)(offsetof(Rml::Vertex, colour)));
+
+	glEnableVertexAttribArray((GLuint)Gfx::VertexAttribute::TexCoord0);
+	glVertexAttribPointer((GLuint)Gfx::VertexAttribute::TexCoord0, 2, GL_FLOAT, GL_FALSE, sizeof(Rml::Vertex),
+		(const GLvoid*)(offsetof(Rml::Vertex, tex_coord)));
+
+	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo);
+	glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(int) * num_indices, (const void*)indices, draw_usage);
+	glBindVertexArray(0);
+
+	Gfx::CheckGLError("CompileGeometry");
+
+	Gfx::CompiledGeometryData* geometry = new Gfx::CompiledGeometryData;
+	geometry->texture = (GLuint)texture;
+	geometry->vao = vao;
+	geometry->vbo = vbo;
+	geometry->ibo = ibo;
+	geometry->draw_count = num_indices;
+
+	return (Rml::CompiledGeometryHandle)geometry;
+}
+
+void RenderInterface_GL3::RenderCompiledGeometry(Rml::CompiledGeometryHandle handle, const Rml::Vector2f& translation)
+{
+	Gfx::CompiledGeometryData* geometry = (Gfx::CompiledGeometryData*)handle;
+
+	if (geometry->texture)
+	{
+		glUseProgram(shaders->program_texture.id);
+		glBindTexture(GL_TEXTURE_2D, geometry->texture);
+		SubmitTransformUniform(ProgramId::Texture, shaders->program_texture.uniform_locations[(size_t)Gfx::ProgramUniform::Transform]);
+		glUniform2fv(shaders->program_texture.uniform_locations[(size_t)Gfx::ProgramUniform::Translate], 1, &translation.x);
+	}
+	else
+	{
+		glUseProgram(shaders->program_color.id);
+		glBindTexture(GL_TEXTURE_2D, 0);
+		SubmitTransformUniform(ProgramId::Color, shaders->program_color.uniform_locations[(size_t)Gfx::ProgramUniform::Transform]);
+		glUniform2fv(shaders->program_color.uniform_locations[(size_t)Gfx::ProgramUniform::Translate], 1, &translation.x);
+	}
+
+	glBindVertexArray(geometry->vao);
+	glDrawElements(GL_TRIANGLES, geometry->draw_count, GL_UNSIGNED_INT, (const GLvoid*)0);
+
+	Gfx::CheckGLError("RenderCompiledGeometry");
+}
+
+void RenderInterface_GL3::ReleaseCompiledGeometry(Rml::CompiledGeometryHandle handle)
+{
+	Gfx::CompiledGeometryData* geometry = (Gfx::CompiledGeometryData*)handle;
+
+	glDeleteVertexArrays(1, &geometry->vao);
+	glDeleteBuffers(1, &geometry->vbo);
+	glDeleteBuffers(1, &geometry->ibo);
+
+	delete geometry;
+}
+
+void RenderInterface_GL3::EnableScissorRegion(bool enable)
+{
+	ScissoringState new_state = ScissoringState::Disable;
+
+	if (enable)
+		new_state = (transform_active ? ScissoringState::Stencil : ScissoringState::Scissor);
+
+	if (new_state != scissoring_state)
+	{
+		// Disable old
+		if (scissoring_state == ScissoringState::Scissor)
+			glDisable(GL_SCISSOR_TEST);
+		else if (scissoring_state == ScissoringState::Stencil)
+			glStencilFunc(GL_ALWAYS, 1, GLuint(-1));
+
+		// Enable new
+		if (new_state == ScissoringState::Scissor)
+			glEnable(GL_SCISSOR_TEST);
+		else if (new_state == ScissoringState::Stencil)
+			glStencilFunc(GL_EQUAL, 1, GLuint(-1));
+
+		scissoring_state = new_state;
+	}
+}
+
+void RenderInterface_GL3::SetScissorRegion(int x, int y, int width, int height)
+{
+	if (transform_active)
+	{
+		const float left = float(x);
+		const float right = float(x + width);
+		const float top = float(y);
+		const float bottom = float(y + height);
+
+		Rml::Vertex vertices[4];
+		vertices[0].position = {left, top};
+		vertices[1].position = {right, top};
+		vertices[2].position = {right, bottom};
+		vertices[3].position = {left, bottom};
+
+		int indices[6] = {0, 2, 1, 0, 3, 2};
+
+		glClear(GL_STENCIL_BUFFER_BIT);
+		glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
+		glStencilFunc(GL_ALWAYS, 1, GLuint(-1));
+		glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);
+
+		RenderGeometry(vertices, 4, indices, 6, 0, Rml::Vector2f(0, 0));
+
+		glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
+		glStencilFunc(GL_EQUAL, 1, GLuint(-1));
+		glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
+	}
+	else
+	{
+		glScissor(x, viewport_height - (y + height), width, height);
+	}
+}
+
+// Set to byte packing, or the compiler will expand our struct, which means it won't read correctly from file
+#pragma pack(1)
+struct TGAHeader {
+	char idLength;
+	char colourMapType;
+	char dataType;
+	short int colourMapOrigin;
+	short int colourMapLength;
+	char colourMapDepth;
+	short int xOrigin;
+	short int yOrigin;
+	short int width;
+	short int height;
+	char bitsPerPixel;
+	char imageDescriptor;
+};
+// Restore packing
+#pragma pack()
+
+bool RenderInterface_GL3::LoadTexture(Rml::TextureHandle& texture_handle, Rml::Vector2i& texture_dimensions, const Rml::String& source)
+{
+	Rml::FileInterface* file_interface = Rml::GetFileInterface();
+	Rml::FileHandle file_handle = file_interface->Open(source);
+	if (!file_handle)
+	{
+		return false;
+	}
+
+	file_interface->Seek(file_handle, 0, SEEK_END);
+	size_t buffer_size = file_interface->Tell(file_handle);
+	file_interface->Seek(file_handle, 0, SEEK_SET);
+
+	if (buffer_size <= sizeof(TGAHeader))
+	{
+		Rml::Log::Message(Rml::Log::LT_ERROR, "Texture file size is smaller than TGAHeader, file is not a valid TGA image.");
+		file_interface->Close(file_handle);
+		return false;
+	}
+
+	using Rml::byte;
+	byte* buffer = new byte[buffer_size];
+	file_interface->Read(buffer, buffer_size, file_handle);
+	file_interface->Close(file_handle);
+
+	TGAHeader header;
+	memcpy(&header, buffer, sizeof(TGAHeader));
+
+	int color_mode = header.bitsPerPixel / 8;
+	int image_size = header.width * header.height * 4; // We always make 32bit textures
+
+	if (header.dataType != 2)
+	{
+		Rml::Log::Message(Rml::Log::LT_ERROR, "Only 24/32bit uncompressed TGAs are supported.");
+		delete[] buffer;
+		return false;
+	}
+
+	// Ensure we have at least 3 colors
+	if (color_mode < 3)
+	{
+		Rml::Log::Message(Rml::Log::LT_ERROR, "Only 24 and 32bit textures are supported.");
+		delete[] buffer;
+		return false;
+	}
+
+	const byte* image_src = buffer + sizeof(TGAHeader);
+	byte* image_dest = new byte[image_size];
+
+	// Targa is BGR, swap to RGB and flip Y axis
+	for (long y = 0; y < header.height; y++)
+	{
+		long read_index = y * header.width * color_mode;
+		long write_index = ((header.imageDescriptor & 32) != 0) ? read_index : (header.height - y - 1) * header.width * 4;
+		for (long x = 0; x < header.width; x++)
+		{
+			image_dest[write_index] = image_src[read_index + 2];
+			image_dest[write_index + 1] = image_src[read_index + 1];
+			image_dest[write_index + 2] = image_src[read_index];
+			if (color_mode == 4)
+			{
+				const int alpha = image_src[read_index + 3];
+#ifdef RMLUI_SRGB_PREMULTIPLIED_ALPHA
+				image_dest[write_index + 0] = (image_dest[write_index + 0] * alpha) / 255;
+				image_dest[write_index + 1] = (image_dest[write_index + 1] * alpha) / 255;
+				image_dest[write_index + 2] = (image_dest[write_index + 2] * alpha) / 255;
+#endif
+				image_dest[write_index + 3] = (byte)alpha;
+			}
+			else
+			{
+				image_dest[write_index + 3] = 255;
+			}
+
+			write_index += 4;
+			read_index += color_mode;
+		}
+	}
+
+	texture_dimensions.x = header.width;
+	texture_dimensions.y = header.height;
+
+	bool success = GenerateTexture(texture_handle, image_dest, texture_dimensions);
+
+	delete[] image_dest;
+	delete[] buffer;
+
+	return success;
+}
+
+bool RenderInterface_GL3::GenerateTexture(Rml::TextureHandle& texture_handle, const Rml::byte* source, const Rml::Vector2i& source_dimensions)
+{
+	GLuint texture_id = 0;
+	glGenTextures(1, &texture_id);
+	if (texture_id == 0)
+	{
+		Rml::Log::Message(Rml::Log::LT_ERROR, "Failed to generate texture.");
+		return false;
+	}
+
+	glBindTexture(GL_TEXTURE_2D, texture_id);
+
+	GLint internal_format = GL_RGBA8;
+	glTexImage2D(GL_TEXTURE_2D, 0, internal_format, source_dimensions.x, source_dimensions.y, 0, GL_RGBA, GL_UNSIGNED_BYTE, source);
+	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+
+	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+
+	texture_handle = (Rml::TextureHandle)texture_id;
+
+	return true;
+}
+
+void RenderInterface_GL3::ReleaseTexture(Rml::TextureHandle texture_handle)
+{
+	glDeleteTextures(1, (GLuint*)&texture_handle);
+}
+
+void RenderInterface_GL3::SetTransform(const Rml::Matrix4f* new_transform)
+{
+	transform_active = (new_transform != nullptr);
+	transform = projection * (new_transform ? *new_transform : Rml::Matrix4f::Identity());
+	transform_dirty_state = ProgramId::All;
+}
+
+void RenderInterface_GL3::SubmitTransformUniform(ProgramId program_id, int uniform_location)
+{
+	if ((int)program_id & (int)transform_dirty_state)
+	{
+		glUniformMatrix4fv(uniform_location, 1, false, transform.data());
+		transform_dirty_state = ProgramId((int)transform_dirty_state & ~(int)program_id);
+	}
+}
+
+bool RmlGL3::Initialize(Rml::String* out_message)
+{
+#if defined RMLUI_PLATFORM_EMSCRIPTEN
+	if (out_message)
+		*out_message = "Started Emscripten WebGL renderer.";
+#else
+	const int gl_version = gladLoaderLoadGL();
+	if (gl_version == 0)
+	{
+		if (out_message)
+			*out_message = "Failed to initialize OpenGL context.";
+		return false;
+	}
+
+	if (out_message)
+		*out_message = Rml::CreateString(128, "Loaded OpenGL %d.%d.", GLAD_VERSION_MAJOR(gl_version), GLAD_VERSION_MINOR(gl_version));
+#endif
+
+	return true;
+}
+
+void RmlGL3::Shutdown()
+{
+#if !defined RMLUI_PLATFORM_EMSCRIPTEN
+	gladLoaderUnloadGL();
+#endif
+}

+ 58 - 39
Samples/basic/sfml2/src/RenderInterfaceSFML.h → Backends/RmlUi_Renderer_GL3.h

@@ -3,7 +3,7 @@
  *
  * For the latest information, see http://github.com/mikke89/RmlUi
  *
- * Copyright (c) 2008-2010 Nuno Silva
+ * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd
  * Copyright (c) 2019 The RmlUi Team, and contributors
  *
  * Permission is hereby granted, free of charge, to any person obtaining a copy
@@ -15,7 +15,7 @@
  *
  * The above copyright notice and this permission notice shall be included in
  * all copies or substantial portions of the Software.
- * 
+ *
  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
@@ -25,66 +25,85 @@
  * THE SOFTWARE.
  *
  */
-#ifndef RENDERINTERFACESFML_H
-#define RENDERINTERFACESFML_H
-
-// NOTE: uncomment this only when you want to use the
-// OpenGL Extension Wrangler Library (GLEW)
-//#define ENABLE_GLEW
 
-// if the OpenGL Extension Wrangler Library (GLEW) should be used include it
-#ifdef ENABLE_GLEW
-#include <GL/glew.h>
-#endif
+#ifndef RMLUI_BACKENDS_RENDERER_GL3_H
+#define RMLUI_BACKENDS_RENDERER_GL3_H
 
 #include <RmlUi/Core/RenderInterface.h>
-#include <SFML/Graphics.hpp>
+#include <RmlUi/Core/Types.h>
 
-// if the OpenGL Extension Wrangler Library (GLEW) should not be used
-// include the standard OpenGL library
-#ifndef ENABLE_GLEW
-#include "../../../shell/include/ShellOpenGL.h"
-#endif
+namespace Gfx {
+struct ShadersData;
+}
 
-class RmlUiSFMLRenderer : public Rml::RenderInterface
-{
+class RenderInterface_GL3 : public Rml::RenderInterface {
 public:
-	RmlUiSFMLRenderer();
+	RenderInterface_GL3();
+	~RenderInterface_GL3();
+
+	// Returns true if the renderer was successfully constructed.
+	explicit operator bool() const { return static_cast<bool>(shaders); }
 
-	/// Sets the window
-	void SetWindow(sf::RenderWindow *Window);
+	// The viewport should be updated whenever the window size changes.
+	void SetViewport(int viewport_width, int viewport_height);
 
-	/// Returns the currently assigned window
-	sf::RenderWindow *GetWindow();
+	// Sets up OpenGL states for taking rendering commands from RmlUi.
+	void BeginFrame();
+	void EndFrame();
 
-	/// Called by RmlUi when it wants to render geometry that it does not wish to optimise.
-	void RenderGeometry(Rml::Vertex* vertices, int num_vertices, int* indices, int num_indices, Rml::TextureHandle texture, const Rml::Vector2f& translation) override;
+	// Optional, can be used to clear the framebuffer.
+	void Clear();
 
-	/// Called by RmlUi when it wants to compile geometry it believes will be static for the forseeable future.
-	Rml::CompiledGeometryHandle CompileGeometry(Rml::Vertex* vertices, int num_vertices, int* indices, int num_indices, Rml::TextureHandle texture) override;
+	// -- Inherited from Rml::RenderInterface --
 
-	/// Called by RmlUi when it wants to render application-compiled geometry.
+	void RenderGeometry(Rml::Vertex* vertices, int num_vertices, int* indices, int num_indices, Rml::TextureHandle texture,
+		const Rml::Vector2f& translation) override;
+
+	Rml::CompiledGeometryHandle CompileGeometry(Rml::Vertex* vertices, int num_vertices, int* indices, int num_indices,
+		Rml::TextureHandle texture) override;
 	void RenderCompiledGeometry(Rml::CompiledGeometryHandle geometry, const Rml::Vector2f& translation) override;
-	/// Called by RmlUi when it wants to release application-compiled geometry.
 	void ReleaseCompiledGeometry(Rml::CompiledGeometryHandle geometry) override;
 
-	/// Called by RmlUi when it wants to enable or disable scissoring to clip content.
 	void EnableScissorRegion(bool enable) override;
-	/// Called by RmlUi when it wants to change the scissor region.
 	void SetScissorRegion(int x, int y, int width, int height) override;
 
-	/// Called by RmlUi when a texture is required by the library.
 	bool LoadTexture(Rml::TextureHandle& texture_handle, Rml::Vector2i& texture_dimensions, const Rml::String& source) override;
-	/// Called by RmlUi when a texture is required to be built from an internally-generated sequence of pixels.
 	bool GenerateTexture(Rml::TextureHandle& texture_handle, const Rml::byte* source, const Rml::Vector2i& source_dimensions) override;
-	/// Called by RmlUi when a loaded texture is no longer required.
 	void ReleaseTexture(Rml::TextureHandle texture_handle) override;
 
-private:
-	void initViewport();
+	void SetTransform(const Rml::Matrix4f* transform) override;
+
+	// Can be passed to RenderGeometry() to enable texture rendering without changing the bound texture.
+	static const Rml::TextureHandle TextureEnableWithoutBinding = Rml::TextureHandle(-1);
 
 private:
-	sf::RenderWindow *MyWindow;
+	enum class ProgramId { None, Texture = 1, Color = 2, All = (Texture | Color) };
+	void SubmitTransformUniform(ProgramId program_id, int uniform_location);
+
+	Rml::Matrix4f transform, projection;
+	ProgramId transform_dirty_state = ProgramId::All;
+	bool transform_active = false;
+
+	enum class ScissoringState { Disable, Scissor, Stencil };
+	ScissoringState scissoring_state = ScissoringState::Disable;
+
+	int viewport_width = 0;
+	int viewport_height = 0;
+
+	Rml::UniquePtr<Gfx::ShadersData> shaders;
 };
 
+/**
+    Helper functions for the OpenGL 3 renderer.
+ */
+namespace RmlGL3 {
+
+// Loads OpenGL functions. Optionally, the out message describes the loaded GL version or an error message on failure.
+bool Initialize(Rml::String* out_message = nullptr);
+
+// Unloads OpenGL functions.
+void Shutdown();
+
+} // namespace RmlGL3
+
 #endif

+ 155 - 0
Backends/RmlUi_Renderer_SDL.cpp

@@ -0,0 +1,155 @@
+/*
+ * This source file is part of RmlUi, the HTML/CSS Interface Middleware
+ *
+ * For the latest information, see http://github.com/mikke89/RmlUi
+ *
+ * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd
+ * Copyright (c) 2019 The RmlUi Team, and contributors
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ */
+
+#include "RmlUi_Renderer_SDL.h"
+#include <RmlUi/Core/Core.h>
+#include <RmlUi/Core/FileInterface.h>
+#include <RmlUi/Core/Types.h>
+#include <SDL.h>
+#include <SDL_image.h>
+
+RenderInterface_SDL::RenderInterface_SDL(SDL_Renderer* renderer) : renderer(renderer) {}
+
+void RenderInterface_SDL::BeginFrame()
+{
+	SDL_RenderSetViewport(renderer, nullptr);
+	SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255);
+	SDL_RenderClear(renderer);
+	SDL_SetRenderDrawBlendMode(renderer, SDL_BLENDMODE_BLEND);
+}
+
+void RenderInterface_SDL::EndFrame() {}
+
+void RenderInterface_SDL::RenderGeometry(Rml::Vertex* vertices, int num_vertices, int* indices, int num_indices, const Rml::TextureHandle texture,
+	const Rml::Vector2f& translation)
+{
+	SDL_FPoint* positions = new SDL_FPoint[num_vertices];
+
+	for (int i = 0; i < num_vertices; i++)
+	{
+		positions[i].x = vertices[i].position.x + translation.x;
+		positions[i].y = vertices[i].position.y + translation.y;
+	}
+
+	SDL_Texture* sdl_texture = (SDL_Texture*)texture;
+
+	SDL_RenderGeometryRaw(renderer, sdl_texture, &positions[0].x, sizeof(SDL_FPoint), (const SDL_Color*)&vertices->colour, sizeof(Rml::Vertex),
+		&vertices->tex_coord.x, sizeof(Rml::Vertex), num_vertices, indices, num_indices, 4);
+
+	delete[] positions;
+}
+
+void RenderInterface_SDL::EnableScissorRegion(bool enable)
+{
+	if (enable)
+		SDL_RenderSetClipRect(renderer, &rect_scissor);
+	else
+		SDL_RenderSetClipRect(renderer, nullptr);
+
+	scissor_region_enabled = enable;
+}
+
+void RenderInterface_SDL::SetScissorRegion(int x, int y, int width, int height)
+{
+	rect_scissor.x = x;
+	rect_scissor.y = y;
+	rect_scissor.w = width;
+	rect_scissor.h = height;
+
+	if (scissor_region_enabled)
+		SDL_RenderSetClipRect(renderer, &rect_scissor);
+}
+
+bool RenderInterface_SDL::LoadTexture(Rml::TextureHandle& texture_handle, Rml::Vector2i& texture_dimensions, const Rml::String& source)
+{
+	Rml::FileInterface* file_interface = Rml::GetFileInterface();
+	Rml::FileHandle file_handle = file_interface->Open(source);
+	if (!file_handle)
+		return false;
+
+	file_interface->Seek(file_handle, 0, SEEK_END);
+	size_t buffer_size = file_interface->Tell(file_handle);
+	file_interface->Seek(file_handle, 0, SEEK_SET);
+
+	char* buffer = new char[buffer_size];
+	file_interface->Read(buffer, buffer_size, file_handle);
+	file_interface->Close(file_handle);
+
+	const size_t i = source.rfind('.');
+	Rml::String extension = (i == Rml::String::npos ? Rml::String() : source.substr(i + 1));
+
+	SDL_Surface* surface = IMG_LoadTyped_RW(SDL_RWFromMem(buffer, int(buffer_size)), 1, extension.c_str());
+
+	bool success = false;
+
+	if (surface)
+	{
+		SDL_Texture* texture = SDL_CreateTextureFromSurface(renderer, surface);
+
+		if (texture)
+		{
+			texture_handle = (Rml::TextureHandle)texture;
+			texture_dimensions = Rml::Vector2i(surface->w, surface->h);
+			success = true;
+		}
+
+		SDL_FreeSurface(surface);
+	}
+
+	delete[] buffer;
+
+	return success;
+}
+
+bool RenderInterface_SDL::GenerateTexture(Rml::TextureHandle& texture_handle, const Rml::byte* source, const Rml::Vector2i& source_dimensions)
+{
+#if SDL_BYTEORDER == SDL_BIG_ENDIAN
+	Uint32 rmask = 0xff000000;
+	Uint32 gmask = 0x00ff0000;
+	Uint32 bmask = 0x0000ff00;
+	Uint32 amask = 0x000000ff;
+#else
+	Uint32 rmask = 0x000000ff;
+	Uint32 gmask = 0x0000ff00;
+	Uint32 bmask = 0x00ff0000;
+	Uint32 amask = 0xff000000;
+#endif
+
+	SDL_Surface* surface =
+		SDL_CreateRGBSurfaceFrom((void*)source, source_dimensions.x, source_dimensions.y, 32, source_dimensions.x * 4, rmask, gmask, bmask, amask);
+	SDL_Texture* texture = SDL_CreateTextureFromSurface(renderer, surface);
+	SDL_SetTextureBlendMode(texture, SDL_BLENDMODE_BLEND);
+	SDL_FreeSurface(surface);
+	texture_handle = (Rml::TextureHandle)texture;
+	return true;
+}
+
+void RenderInterface_SDL::ReleaseTexture(Rml::TextureHandle texture_handle)
+{
+	SDL_DestroyTexture((SDL_Texture*)texture_handle);
+}

+ 61 - 66
Samples/basic/sdl2/src/RenderInterfaceSDL2.h → Backends/RmlUi_Renderer_SDL.h

@@ -1,66 +1,61 @@
-/*
- * This source file is part of RmlUi, the HTML/CSS Interface Middleware
- *
- * For the latest information, see http://github.com/mikke89/RmlUi
- *
- * Copyright (c) 2008-2010 Nuno Silva
- * Copyright (c) 2019 The RmlUi Team, and contributors
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- * 
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- *
- */
-#ifndef RENDERINTERFACESDL2_H
-#define RENDERINTERFACESDL2_H
-
-#include <RmlUi/Core/RenderInterface.h>
-
-#include <SDL.h>
-#include <GL/glew.h>
-
-#if !(SDL_VIDEO_RENDER_OGL)
-    #error "Only the opengl sdl backend is supported."
-#endif
-
-
-class RmlUiSDL2Renderer : public Rml::RenderInterface
-{
-public:
-	RmlUiSDL2Renderer(SDL_Renderer* renderer, SDL_Window* screen);
-
-	/// Called by RmlUi when it wants to render geometry that it does not wish to optimise.
-	void RenderGeometry(Rml::Vertex* vertices, int num_vertices, int* indices, int num_indices, Rml::TextureHandle texture, const Rml::Vector2f& translation) override;
-
-	/// Called by RmlUi when it wants to enable or disable scissoring to clip content.
-	void EnableScissorRegion(bool enable) override;
-	/// Called by RmlUi when it wants to change the scissor region.
-	void SetScissorRegion(int x, int y, int width, int height) override;
-
-	/// Called by RmlUi when a texture is required by the library.
-	bool LoadTexture(Rml::TextureHandle& texture_handle, Rml::Vector2i& texture_dimensions, const Rml::String& source) override;
-	/// Called by RmlUi when a texture is required to be built from an internally-generated sequence of pixels.
-	bool GenerateTexture(Rml::TextureHandle& texture_handle, const Rml::byte* source, const Rml::Vector2i& source_dimensions) override;
-	/// Called by RmlUi when a loaded texture is no longer required.
-	void ReleaseTexture(Rml::TextureHandle texture_handle) override;
-
-private:
-    SDL_Renderer* mRenderer;
-    SDL_Window* mScreen;
-};
-
-#endif
+/*
+ * This source file is part of RmlUi, the HTML/CSS Interface Middleware
+ *
+ * For the latest information, see http://github.com/mikke89/RmlUi
+ *
+ * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd
+ * Copyright (c) 2019 The RmlUi Team, and contributors
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ */
+
+#ifndef RMLUI_BACKENDS_RENDERER_SDL_H
+#define RMLUI_BACKENDS_RENDERER_SDL_H
+
+#include <RmlUi/Core/RenderInterface.h>
+#include <SDL.h>
+
+class RenderInterface_SDL : public Rml::RenderInterface {
+public:
+	RenderInterface_SDL(SDL_Renderer* renderer);
+
+	// Sets up OpenGL states for taking rendering commands from RmlUi.
+	void BeginFrame();
+	void EndFrame();
+
+	// -- Inherited from Rml::RenderInterface --
+
+	void RenderGeometry(Rml::Vertex* vertices, int num_vertices, int* indices, int num_indices, Rml::TextureHandle texture,
+		const Rml::Vector2f& translation) override;
+
+	void EnableScissorRegion(bool enable) override;
+	void SetScissorRegion(int x, int y, int width, int height) override;
+
+	bool LoadTexture(Rml::TextureHandle& texture_handle, Rml::Vector2i& texture_dimensions, const Rml::String& source) override;
+	bool GenerateTexture(Rml::TextureHandle& texture_handle, const Rml::byte* source, const Rml::Vector2i& source_dimensions) override;
+	void ReleaseTexture(Rml::TextureHandle texture_handle) override;
+
+private:
+	SDL_Renderer* renderer;
+	SDL_Rect rect_scissor = {};
+	bool scissor_region_enabled = false;
+};
+
+#endif

+ 87 - 0
CMake/BackendFileList.cmake

@@ -0,0 +1,87 @@
+set(BACKEND_COMMON_HDR_FILES
+	${PROJECT_SOURCE_DIR}/Backends/RmlUi_Backend.h
+)
+
+set(Win32_GL2_SRC_FILES
+	${PROJECT_SOURCE_DIR}/Backends/RmlUi_Platform_Win32.cpp
+	${PROJECT_SOURCE_DIR}/Backends/RmlUi_Renderer_GL2.cpp
+	${PROJECT_SOURCE_DIR}/Backends/RmlUi_Backend_Win32_GL2.cpp
+)
+set(Win32_GL2_HDR_FILES
+	${PROJECT_SOURCE_DIR}/Backends/RmlUi_Platform_Win32.h
+	${PROJECT_SOURCE_DIR}/Backends/RmlUi_Renderer_GL2.h
+	${PROJECT_SOURCE_DIR}/Backends/RmlUi_Include_Windows.h
+)
+
+set(X11_GL2_SRC_FILES
+	${PROJECT_SOURCE_DIR}/Backends/RmlUi_Platform_X11.cpp
+	${PROJECT_SOURCE_DIR}/Backends/RmlUi_Renderer_GL2.cpp	
+	${PROJECT_SOURCE_DIR}/Backends/RmlUi_Backend_X11_GL2.cpp
+)
+set(X11_GL2_HDR_FILES
+	${PROJECT_SOURCE_DIR}/Backends/RmlUi_Platform_X11.h
+	${PROJECT_SOURCE_DIR}/Backends/RmlUi_Renderer_GL2.h
+	${PROJECT_SOURCE_DIR}/Backends/RmlUi_Include_Xlib.h
+)
+
+set(SDL_GL2_SRC_FILES
+	${PROJECT_SOURCE_DIR}/Backends/RmlUi_Platform_SDL.cpp
+	${PROJECT_SOURCE_DIR}/Backends/RmlUi_Renderer_GL2.cpp
+	${PROJECT_SOURCE_DIR}/Backends/RmlUi_Backend_SDL_GL2.cpp
+)
+set(SDL_GL2_HDR_FILES
+	${PROJECT_SOURCE_DIR}/Backends/RmlUi_Platform_SDL.h
+	${PROJECT_SOURCE_DIR}/Backends/RmlUi_Renderer_GL2.h
+)
+
+set(SDL_GL3_SRC_FILES
+	${PROJECT_SOURCE_DIR}/Backends/RmlUi_Platform_SDL.cpp
+	${PROJECT_SOURCE_DIR}/Backends/RmlUi_Renderer_GL3.cpp
+	${PROJECT_SOURCE_DIR}/Backends/RmlUi_Backend_SDL_GL3.cpp
+)
+set(SDL_GL3_HDR_FILES
+	${PROJECT_SOURCE_DIR}/Backends/RmlUi_Platform_SDL.h
+	${PROJECT_SOURCE_DIR}/Backends/RmlUi_Renderer_GL3.h
+	${PROJECT_SOURCE_DIR}/Backends/RmlUi_Include_GL3.h
+)
+
+set(SDL_SDLrenderer_SRC_FILES
+	${PROJECT_SOURCE_DIR}/Backends/RmlUi_Renderer_SDL.cpp
+	${PROJECT_SOURCE_DIR}/Backends/RmlUi_Platform_SDL.cpp
+	${PROJECT_SOURCE_DIR}/Backends/RmlUi_Backend_SDL_SDLrenderer.cpp
+)
+set(SDL_SDLrenderer_HDR_FILES
+	${PROJECT_SOURCE_DIR}/Backends/RmlUi_Platform_SDL.h
+	${PROJECT_SOURCE_DIR}/Backends/RmlUi_Renderer_SDL.h
+)
+
+set(SFML_GL2_SRC_FILES
+	${PROJECT_SOURCE_DIR}/Backends/RmlUi_Platform_SFML.cpp
+	${PROJECT_SOURCE_DIR}/Backends/RmlUi_Renderer_GL2.cpp
+	${PROJECT_SOURCE_DIR}/Backends/RmlUi_Backend_SFML_GL2.cpp
+)
+set(SFML_GL2_HDR_FILES
+	${PROJECT_SOURCE_DIR}/Backends/RmlUi_Platform_SFML.h
+	${PROJECT_SOURCE_DIR}/Backends/RmlUi_Renderer_GL2.h
+)
+
+set(GLFW_GL2_SRC_FILES
+	${PROJECT_SOURCE_DIR}/Backends/RmlUi_Platform_GLFW.cpp
+	${PROJECT_SOURCE_DIR}/Backends/RmlUi_Renderer_GL2.cpp
+	${PROJECT_SOURCE_DIR}/Backends/RmlUi_Backend_GLFW_GL2.cpp
+)
+set(GLFW_GL2_HDR_FILES
+	${PROJECT_SOURCE_DIR}/Backends/RmlUi_Platform_GLFW.h
+	${PROJECT_SOURCE_DIR}/Backends/RmlUi_Renderer_GL2.h
+)
+
+set(GLFW_GL3_SRC_FILES
+	${PROJECT_SOURCE_DIR}/Backends/RmlUi_Platform_GLFW.cpp
+	${PROJECT_SOURCE_DIR}/Backends/RmlUi_Renderer_GL3.cpp
+	${PROJECT_SOURCE_DIR}/Backends/RmlUi_Backend_GLFW_GL3.cpp
+)
+set(GLFW_GL3_HDR_FILES
+	${PROJECT_SOURCE_DIR}/Backends/RmlUi_Platform_GLFW.h
+	${PROJECT_SOURCE_DIR}/Backends/RmlUi_Renderer_GL3.h
+	${PROJECT_SOURCE_DIR}/Backends/RmlUi_Include_GL3.h
+)

+ 0 - 36
CMake/Modules/FindCarbon.cmake

@@ -1,36 +0,0 @@
-# - Try to find Carbon
-# Once done, this will define
-#
-#  Carbon_FOUND - system has Carbon
-#  Carbon_INCLUDE_DIRS - the Carbon include directories 
-#  Carbon_LIBRARIES - link these to use Carbon
-
-include(FindPkgMacros)
-findpkg_begin(Carbon)
-
-# construct search paths
-set(Carbon_PREFIX_PATH ${Carbon_HOME} $ENV{Carbon_HOME}
-  ${OGRE_HOME} $ENV{OGRE_HOME})
-create_search_paths(Carbon)
-# redo search if prefix path changed
-clear_if_changed(Carbon_PREFIX_PATH
-  Carbon_LIBRARY_FWK
-  Carbon_LIBRARY_REL
-  Carbon_LIBRARY_DBG
-  Carbon_INCLUDE_DIR
-)
-
-set(Carbon_LIBRARY_NAMES Carbon)
-get_debug_names(Carbon_LIBRARY_NAMES)
-
-use_pkgconfig(Carbon_PKGC Carbon)
-
-findpkg_framework(Carbon)
-
-find_path(Carbon_INCLUDE_DIR NAMES Carbon.h HINTS ${Carbon_INC_SEARCH_PATH} ${Carbon_PKGC_INCLUDE_DIRS} PATH_SUFFIXES Carbon)
-find_library(Carbon_LIBRARY_REL NAMES ${Carbon_LIBRARY_NAMES} HINTS ${Carbon_LIB_SEARCH_PATH} ${Carbon_PKGC_LIBRARY_DIRS})
-find_library(Carbon_LIBRARY_DBG NAMES ${Carbon_LIBRARY_NAMES_DBG} HINTS ${Carbon_LIB_SEARCH_PATH} ${Carbon_PKGC_LIBRARY_DIRS})
-make_library_set(Carbon_LIBRARY)
-
-findpkg_finish(Carbon)
-add_parent_dir(Carbon_INCLUDE_DIRS Carbon_INCLUDE_DIR)

+ 10 - 0
CMake/Modules/FindSDL2.cmake

@@ -67,6 +67,16 @@
 # (To distribute this file outside of CMake, substitute the full
 #  License text for the above reference.)
 
+# Look for the library in config mode first.
+find_package(SDL2 CONFIG)
+if(SDL2_FOUND AND TARGET SDL2::SDL2)
+  message(STATUS "Found SDL2 in config mode, version ${SDL2_VERSION}.")
+  set(SDL2_LIBRARY "SDL2::SDL2")
+  return()
+else()
+  message(STATUS "Looking for SDL2 in module mode.")
+endif()
+
 SET(SDL2_SEARCH_PATHS
   ~/Library/Frameworks
   /Library/Frameworks

+ 4 - 73
CMake/SampleFileList.cmake

@@ -1,22 +1,17 @@
 # This file was auto-generated with gen_samplelists.sh
 
 set(shell_HDR_FILES
-    ${PROJECT_SOURCE_DIR}/Samples/shell/src/precompiled.h
-    ${PROJECT_SOURCE_DIR}/Samples/shell/include/Input.h
+    ${PROJECT_SOURCE_DIR}/Samples/shell/include/PlatformExtensions.h
+    ${PROJECT_SOURCE_DIR}/Samples/shell/include/RendererExtensions.h
     ${PROJECT_SOURCE_DIR}/Samples/shell/include/Shell.h
     ${PROJECT_SOURCE_DIR}/Samples/shell/include/ShellFileInterface.h
-    ${PROJECT_SOURCE_DIR}/Samples/shell/include/ShellOpenGL.h
-    ${PROJECT_SOURCE_DIR}/Samples/shell/include/ShellRenderInterfaceExtensions.h
-    ${PROJECT_SOURCE_DIR}/Samples/shell/include/ShellRenderInterfaceOpenGL.h
-    ${PROJECT_SOURCE_DIR}/Samples/shell/include/ShellSystemInterface.h
 )
 
 set(shell_SRC_FILES
-    ${PROJECT_SOURCE_DIR}/Samples/shell/src/Input.cpp
+    ${PROJECT_SOURCE_DIR}/Samples/shell/src/PlatformExtensions.cpp
+    ${PROJECT_SOURCE_DIR}/Samples/shell/src/RendererExtensions.cpp
     ${PROJECT_SOURCE_DIR}/Samples/shell/src/Shell.cpp
     ${PROJECT_SOURCE_DIR}/Samples/shell/src/ShellFileInterface.cpp
-    ${PROJECT_SOURCE_DIR}/Samples/shell/src/ShellRenderInterfaceOpenGL.cpp
-    ${PROJECT_SOURCE_DIR}/Samples/shell/src/ShellSystemInterface.cpp
 )
 
 set(animation_HDR_FILES
@@ -115,39 +110,6 @@ set(svg_SRC_FILES
     ${PROJECT_SOURCE_DIR}/Samples/basic/svg/src/main.cpp
 )
 
-set(sdl2_HDR_FILES
-    ${PROJECT_SOURCE_DIR}/Samples/basic/sdl2/src/RenderInterfaceSDL2.h
-    ${PROJECT_SOURCE_DIR}/Samples/basic/sdl2/src/SystemInterfaceSDL2.h
-)
-
-set(sdl2_SRC_FILES
-    ${PROJECT_SOURCE_DIR}/Samples/basic/sdl2/src/main.cpp
-    ${PROJECT_SOURCE_DIR}/Samples/basic/sdl2/src/RenderInterfaceSDL2.cpp
-    ${PROJECT_SOURCE_DIR}/Samples/basic/sdl2/src/SystemInterfaceSDL2.cpp
-)
-
-set(sdl2_sdlrenderer_HDR_FILES
-    ${PROJECT_SOURCE_DIR}/Samples/basic/sdl2_sdlrenderer/src/RenderInterfaceSDL2.h
-    ${PROJECT_SOURCE_DIR}/Samples/basic/sdl2_sdlrenderer/src/SystemInterfaceSDL2.h
-)
-
-set(sdl2_sdlrenderer_SRC_FILES
-    ${PROJECT_SOURCE_DIR}/Samples/basic/sdl2_sdlrenderer/src/main.cpp
-    ${PROJECT_SOURCE_DIR}/Samples/basic/sdl2_sdlrenderer/src/RenderInterfaceSDL2.cpp
-    ${PROJECT_SOURCE_DIR}/Samples/basic/sdl2_sdlrenderer/src/SystemInterfaceSDL2.cpp
-)
-
-set(sfml2_HDR_FILES
-    ${PROJECT_SOURCE_DIR}/Samples/basic/sfml2/src/RenderInterfaceSFML.h
-    ${PROJECT_SOURCE_DIR}/Samples/basic/sfml2/src/SystemInterfaceSFML.h
-)
-
-set(sfml2_SRC_FILES
-    ${PROJECT_SOURCE_DIR}/Samples/basic/sfml2/src/main.cpp
-    ${PROJECT_SOURCE_DIR}/Samples/basic/sfml2/src/RenderInterfaceSFML.cpp
-    ${PROJECT_SOURCE_DIR}/Samples/basic/sfml2/src/SystemInterfaceSFML.cpp
-)
-
 set(tutorial_template_HDR_FILES
 )
 
@@ -276,34 +238,3 @@ set(luainvaders_SRC_FILES
     ${PROJECT_SOURCE_DIR}/Samples/luainvaders/src/Sprite.cpp
 )
 
-# Deal with platform specific sources for sample shell
-if(WIN32)
-       list(APPEND shell_SRC_FILES
-               ${PROJECT_SOURCE_DIR}/Samples/shell/src/win32/ShellWin32.cpp
-               ${PROJECT_SOURCE_DIR}/Samples/shell/src/win32/InputWin32.cpp
-               ${PROJECT_SOURCE_DIR}/Samples/shell/src/win32/ShellRenderInterfaceExtensionsOpenGL_Win32.cpp
-       )
-       list(APPEND shell_HDR_FILES
-               ${PROJECT_SOURCE_DIR}/Samples/shell/include/win32/InputWin32.h
-               ${PROJECT_SOURCE_DIR}/Samples/shell/include/win32/IncludeWindows.h
-       )
-elseif(APPLE)
-       list(APPEND shell_SRC_FILES
-               ${PROJECT_SOURCE_DIR}/Samples/shell/src/macosx/ShellMacOSX.cpp
-               ${PROJECT_SOURCE_DIR}/Samples/shell/src/macosx/InputMacOSX.cpp
-               ${PROJECT_SOURCE_DIR}/Samples/shell/src/macosx/ShellRenderInterfaceExtensionsOpenGL_MacOSX.cpp
-       )
-       list(APPEND shell_HDR_FILES
-               ${PROJECT_SOURCE_DIR}/Samples/shell/include/macosx/InputMacOSX.h
-       )
-else()
-       list(APPEND shell_SRC_FILES
-               ${PROJECT_SOURCE_DIR}/Samples/shell/src/x11/ShellX11.cpp
-               ${PROJECT_SOURCE_DIR}/Samples/shell/src/x11/InputX11.cpp
-               ${PROJECT_SOURCE_DIR}/Samples/shell/src/x11/ShellRenderInterfaceExtensionsOpenGL_X11.cpp
-       )
-       list(APPEND shell_HDR_FILES
-               ${PROJECT_SOURCE_DIR}/Samples/shell/include/x11/InputX11.h
-               ${PROJECT_SOURCE_DIR}/Samples/shell/include/x11/X11MacroZapper.h
-       )
-endif()

+ 1 - 36
CMake/gen_samplelists.sh

@@ -8,7 +8,7 @@ srcdir='${PROJECT_SOURCE_DIR}'
 srcpath=Samples
 samples=( 'shell'
 	'basic/animation' 'basic/benchmark' 'basic/bitmapfont' 'basic/customlog' 'basic/databinding' 'basic/demo' 'basic/drag' 'basic/loaddocument' 'basic/treeview' 'basic/transform'
-	'basic/lottie' 'basic/svg' 'basic/sdl2' 'basic/sdl2_sdlrenderer' 'basic/sfml2'
+	'basic/lottie' 'basic/svg'
 	'tutorial/template' 'tutorial/datagrid' 'tutorial/datagrid_tree' 'tutorial/drag'
 	'invaders' 'luainvaders'
 )
@@ -32,38 +32,3 @@ echo -e "# This file was auto-generated with gen_samplelists.sh\n" >$file
 for sample in ${samples[@]}; do
     printfiles $sample
 done
-
-echo '# Deal with platform specific sources for sample shell' >> $file
-echo 'if(WIN32)' >> $file
-echo '       list(APPEND shell_SRC_FILES' >> $file
-echo '               ${PROJECT_SOURCE_DIR}/Samples/shell/src/win32/ShellWin32.cpp' >> $file
-echo '               ${PROJECT_SOURCE_DIR}/Samples/shell/src/win32/InputWin32.cpp' >> $file
-echo '               ${PROJECT_SOURCE_DIR}/Samples/shell/src/win32/ShellRenderInterfaceExtensionsOpenGL_Win32.cpp' >> $file
-echo '       )' >> $file
-echo '       list(APPEND shell_HDR_FILES' >> $file
-echo '               ${PROJECT_SOURCE_DIR}/Samples/shell/include/win32/InputWin32.h' >> $file
-echo '               ${PROJECT_SOURCE_DIR}/Samples/shell/include/win32/IncludeWindows.h' >> $file
-echo '       )' >> $file
-echo 'elseif(APPLE)' >> $file
-echo '       list(APPEND shell_SRC_FILES' >> $file
-echo '               ${PROJECT_SOURCE_DIR}/Samples/shell/src/macosx/ShellMacOSX.cpp' >> $file
-echo '               ${PROJECT_SOURCE_DIR}/Samples/shell/src/macosx/InputMacOSX.cpp' >> $file
-echo '               ${PROJECT_SOURCE_DIR}/Samples/shell/src/macosx/ShellRenderInterfaceExtensionsOpenGL_MacOSX.cpp' >> $file
-echo '       )' >> $file
-echo '       list(APPEND shell_HDR_FILES' >> $file
-echo '               ${PROJECT_SOURCE_DIR}/Samples/shell/include/macosx/InputMacOSX.h' >> $file
-echo '       )' >> $file
-echo 'else()' >> $file
-echo '       list(APPEND shell_SRC_FILES' >> $file
-echo '               ${PROJECT_SOURCE_DIR}/Samples/shell/src/x11/ShellX11.cpp' >> $file
-echo '               ${PROJECT_SOURCE_DIR}/Samples/shell/src/x11/InputX11.cpp' >> $file
-echo '               ${PROJECT_SOURCE_DIR}/Samples/shell/src/x11/ShellRenderInterfaceExtensionsOpenGL_X11.cpp' >> $file
-echo '       )' >> $file
-echo '       list(APPEND shell_HDR_FILES' >> $file
-echo '               ${PROJECT_SOURCE_DIR}/Samples/shell/include/x11/InputX11.h' >> $file
-echo '               ${PROJECT_SOURCE_DIR}/Samples/shell/include/x11/X11MacroZapper.h' >> $file
-echo '       )' >> $file
-echo 'endif()' >> $file
-
-popd
-

+ 200 - 145
CMakeLists.txt

@@ -69,7 +69,7 @@ list(APPEND CORE_PRIVATE_DEFS RMLUI_VERSION="${RMLUI_VERSION_SHORT}")
 
 if(CMAKE_PROJECT_NAME STREQUAL PROJECT_NAME)
 	option(BUILD_TESTING "" OFF)
-    include(CTest)
+	include(CTest)
 	
 	if(BUILD_TESTING)
 		set(RMLUI_TESTS_ENABLED ON)
@@ -163,6 +163,21 @@ endif()
 
 option(BUILD_SAMPLES "Build samples" OFF)
 
+set(SAMPLES_BACKEND "auto" CACHE STRING "Backend platform and renderer used for the samples.")
+set_property(CACHE SAMPLES_BACKEND PROPERTY STRINGS auto Win32_GL2 X11_GL2 SDL_GL2 SDL_GL3 SDL_SDLrenderer SFML_GL2 GLFW_GL2 GLFW_GL3)
+
+if(SAMPLES_BACKEND STREQUAL "auto")
+	if(EMSCRIPTEN)
+		set(SAMPLES_BACKEND SDL_GL3)
+	elseif(WIN32)
+		set(SAMPLES_BACKEND Win32_GL2)
+	elseif(APPLE)
+		set(SAMPLES_BACKEND SDL_SDLrenderer)
+	else()
+		set(SAMPLES_BACKEND X11_GL2)
+	endif()
+endif()
+
 option(MATRIX_ROW_MAJOR "Use row-major matrices. Column-major matrices are used by default." OFF)
 
 if(APPLE)
@@ -195,6 +210,10 @@ if(WIN32 AND BUILD_SHARED_LIBS AND BUILD_TESTING)
 	message(FATAL_ERROR "-- The RmlUi testing framework cannot be built when using shared libraries on Windows. Please disable either BUILD_SHARED_LIBS or BUILD_TESTING.")
 endif()
 
+if(EMSCRIPTEN AND BUILD_SHARED_LIBS)
+	message(FATAL_ERROR "-- Dynamic libraries not supported when using Emscripten. Please disable BUILD_SHARED_LIBS.")
+endif()
+
 if(NOT BUILD_SHARED_LIBS)
 	list(APPEND CORE_PUBLIC_DEFS -DRMLUI_STATIC_LIB)
 	message("-- Building static libraries. Make sure to #define RMLUI_STATIC_LIB before including RmlUi in your project.")
@@ -322,14 +341,17 @@ include(FileList)
 
 # FreeType
 if(NOT NO_FONT_INTERFACE_DEFAULT)
-	find_package(Freetype REQUIRED)
-	
-	if(MSVC AND FREETYPE_VERSION_STRING STREQUAL "2.11.0")
-		message(WARNING "You are using FreeType version 2.11.0 which introduced an issue that causes a crash on startup on some of the samples. Please avoid this version specifically.")
+	if(EMSCRIPTEN)
+		set(EMSCRIPTEN_FLAGS "${EMSCRIPTEN_FLAGS} -sUSE_FREETYPE=1")
+	else()
+		find_package(Freetype REQUIRED)
+		if(MSVC AND FREETYPE_VERSION_STRING STREQUAL "2.11.0")
+			message(WARNING "You are using FreeType version 2.11.0 which introduced an issue that causes a crash on startup on some of the samples. Please avoid this version specifically.")
+		endif()
+		
+		list(APPEND CORE_LINK_LIBS ${FREETYPE_LIBRARIES})
+		list(APPEND CORE_INCLUDE_DIRS ${FREETYPE_INCLUDE_DIRS})
 	endif()
-	
-	list(APPEND CORE_LINK_LIBS ${FREETYPE_LIBRARIES})
-	list(APPEND CORE_INCLUDE_DIRS ${FREETYPE_INCLUDE_DIRS})
 endif()
 
 # Lua
@@ -537,9 +559,9 @@ if(BUILD_LUA_BINDINGS)
 endif()
 
 if(DISABLE_RTTI_AND_EXCEPTIONS)
-    if( CMAKE_COMPILER_IS_GNUCXX )
+	if( CMAKE_COMPILER_IS_GNUCXX )
 		add_definitions( -fno-rtti -fno-exceptions )
-    elseif( MSVC )
+	elseif( MSVC )
 		add_definitions( -D_HAS_EXCEPTIONS=0 /GR- )
 		if(CMAKE_CXX_FLAGS MATCHES "/EHsc ")
 			string(REPLACE "/EHsc" "" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}")
@@ -552,7 +574,7 @@ if(DISABLE_RTTI_AND_EXCEPTIONS)
 		endif()
 	else()
 		message(STATUS "Could not create build configuration without rtti and exceptions...")
-    endif()
+	endif()
 endif()
 
 
@@ -614,7 +636,10 @@ endmacro()
 
 # Build shell
 if(BUILD_SAMPLES OR BUILD_TESTING)
+	message("-- Adding shell with '${SAMPLES_BACKEND}' backend.")
+	
 	include(SampleFileList)
+	include(BackendFileList)
 	
 	if(NOT BUILD_FRAMEWORK)
 		set(sample_LIBRARIES
@@ -629,60 +654,132 @@ if(BUILD_SAMPLES OR BUILD_TESTING)
 		)
 	endif()
 
-	# Find OpenGL 
-	find_package(OpenGL REQUIRED)
-		   
-	if(OPENGL_FOUND)
-		include_directories(${OPENGL_INCLUDE_DIR})
-		list(APPEND sample_LIBRARIES ${OPENGL_LIBRARIES})
+	set(SAMPLES_DIR opt/RmlUi/Samples CACHE PATH "Path to samples directory.")
+	if(WIN32)
+		mark_as_advanced(SAMPLES_DIR)
 	endif()
 	
-	# Set up required system libraries
-	if(APPLE)
-		include(FindCarbon)
-		find_package(Carbon REQUIRED)
-		
-		if (Carbon_FOUND)
-			include_directories(${Carbon_INCLUDE_DIR})
-			list(APPEND sample_LIBRARIES ${Carbon_LIBRARIES})
-		endif()
-	else()
-		find_package(X11 REQUIRED)
+
+	set(BACKEND_SRC_FILES "${${SAMPLES_BACKEND}_SRC_FILES}")
+	set(BACKEND_HDR_FILES "${${SAMPLES_BACKEND}_HDR_FILES}")
+	
+	if("${BACKEND_SRC_FILES}" STREQUAL "" OR "${BACKEND_HDR_FILES}" STREQUAL "")
+		message(FATAL_ERROR "Unknown samples backend '${SAMPLES_BACKEND}'.")
+	endif()
+	
+	list(APPEND shell_SRC_FILES ${BACKEND_SRC_FILES})
+	list(APPEND shell_HDR_FILES ${BACKEND_HDR_FILES} ${BACKEND_COMMON_HDR_FILES})
+	
+	add_library(shell STATIC ${shell_SRC_FILES} ${shell_HDR_FILES})
+	
+	target_include_directories(shell PUBLIC
+		${PROJECT_SOURCE_DIR}/Backends
+		${PROJECT_SOURCE_DIR}/Samples/shell/include
+	)
+	
+	add_common_target_options(shell)
+	target_link_libraries(shell PUBLIC RmlCore RmlDebugger)
+	
+	# Add OS dependencies.
+	if (WIN32)
+		target_link_libraries(shell PRIVATE shlwapi)
+	elseif(APPLE)
+		target_link_libraries(shell PRIVATE "-framework Cocoa")
+	elseif(UNIX AND NOT APPLE AND NOT EMSCRIPTEN)
+		find_package(X11)
 		if (X11_FOUND)
-			list(APPEND sample_LIBRARIES ${X11_LIBRARIES})
-		# shell/src/x11/InputX11.cpp:InitialiseX11Keymap uses Xkb if
-		# possible instead of XGetKeyboardMapping for performance
-		if(X11_Xkb_FOUND)
-			FIND_PACKAGE_MESSAGE(X11 "Found X11 KBlib: ${X11_X11_LIB}" "[${X11_X11_LIB}][${X11_XkbINCLUDE_DIR}]")
-			add_definitions(-DHAS_X11XKBLIB)
+			message("-- Found X11 library.")
+			target_link_libraries(shell PRIVATE ${X11_LIBRARIES})
+			# Platform_X11 uses Xkb if possible instead of XGetKeyboardMapping for performance.
+			if(X11_Xkb_FOUND)
+				FIND_PACKAGE_MESSAGE(X11 "Found X11 KBlib: ${X11_X11_LIB}" "[${X11_X11_LIB}][${X11_XkbINCLUDE_DIR}]")
+				target_compile_definitions(shell PRIVATE HAS_X11XKBLIB)
+			endif()
 		endif()
+	endif()
+	
+	# Add platform dependencies.
+	if(SAMPLES_BACKEND MATCHES "^X11")		
+		if(NOT X11_FOUND)
+			message(FATAL_ERROR "X11 not found or not supported on this platform, select a different sample backend.")
 		endif()
 	endif()
-   
-	set(SAMPLES_DIR opt/RmlUi/Samples CACHE PATH "path to samples dir")
 	
-	if(WIN32)
-		mark_as_advanced(SAMPLES_DIR)
+	if(SAMPLES_BACKEND MATCHES "^SDL")
+		message("-- Looking for SDL2 library for samples backend.")
+		if(EMSCRIPTEN)
+			set(EMSCRIPTEN_FLAGS "${EMSCRIPTEN_FLAGS} -sUSE_SDL=2 -sUSE_SDL_IMAGE=2 -sSDL2_IMAGE_FORMATS='[tga]'")
+		else()
+			find_package(SDL2 REQUIRED)
+			find_package(SDL2_image REQUIRED)
+			
+			if(NOT SDL2_FOUND)
+				message(FATAL_ERROR "SDL2 not found")
+			elseif(NOT SDL2_IMAGE_FOUND)
+				message(FATAL_ERROR "SDL2_image not found")
+			endif()
+			
+			if(SAMPLES_BACKEND STREQUAL "SDL_GL2")
+				find_package(GLEW REQUIRED)
+				if(NOT GLEW_FOUND)
+					message(FATAL_ERROR "GLEW not found")
+				endif()
+			endif()
+			
+			# Check version requirement for the SDL renderer.
+			if(SAMPLES_BACKEND STREQUAL "SDL_SDLrenderer" AND "${SDL2_VERSION}" VERSION_LESS "2.0.20")
+				message(FATAL_ERROR "SDL2 native renderer backend (${SAMPLES_BACKEND}) requires SDL 2.0.20 (found ${SDL2_VERSION}).")
+			endif()
+			
+			target_include_directories(shell PRIVATE ${SDL2_INCLUDE_DIR} ${SDL2_IMAGE_INCLUDE_DIR} ${GLEW_INCLUDE_DIR})
+			target_link_libraries(shell PRIVATE ${SDL2_LIBRARY} ${SDL2_IMAGE_LIBRARY} ${GLEW_LIBRARIES})
+		endif()
 	endif()
-
-	# The samples and tutorials use the shell library
-	include_directories(${PROJECT_SOURCE_DIR}/Samples/shell/include)
-
-	# Build and install sample shell library
-	add_library(shell STATIC ${shell_SRC_FILES} ${shell_HDR_FILES})
 	
-	if (PRECOMPILED_HEADERS_ENABLED)
-		target_precompile_headers(shell PRIVATE ${PROJECT_SOURCE_DIR}/Samples/shell/src/precompiled.h)
+	if(SAMPLES_BACKEND MATCHES "^SFML")
+		message("-- Looking for SFML 2.x library for samples backend.")
+		if (WIN32)
+			find_package(SFML 2 REQUIRED COMPONENTS graphics window system main)
+		else()
+			find_package(SFML 2 REQUIRED COMPONENTS graphics window system)
+		endif()
+		target_include_directories(shell PRIVATE ${SFML_INCLUDE_DIR})
+		target_link_libraries(shell PRIVATE ${SFML_LIBRARIES})
 	endif()
-
-	if (WIN32)
-		target_link_libraries(shell PUBLIC shlwapi)
+	
+	if(SAMPLES_BACKEND MATCHES "^GLFW")
+		message("-- Looking for GLFW3 library for samples backend.")
+		find_package(glfw3 3.3 CONFIG REQUIRED)
+		target_link_libraries(shell PRIVATE glfw)
+		message("-- Found GLFW version ${glfw3_VERSION}.")
 	endif()
 	
-	target_link_libraries(shell PUBLIC RmlCore)
+	# Add renderer dependencies.
+	if(SAMPLES_BACKEND MATCHES "GL2$")
+		message("-- Adding OpenGL 2 renderer backend.")
+		find_package(OpenGL REQUIRED)
+		target_include_directories(shell PRIVATE ${OPENGL_INCLUDE_DIR})
+		target_link_libraries(shell PRIVATE ${OPENGL_LIBRARIES})
+		target_compile_definitions(shell PRIVATE RMLUI_RENDERER_GL2)
+		if(APPLE)
+			target_compile_definitions(shell PRIVATE GL_SILENCE_DEPRECATION)
+		endif()
+	endif()
 	
-	add_common_target_options(shell)
-
+	if(SAMPLES_BACKEND MATCHES "GL3$")
+		message("-- Adding OpenGL 3 renderer backend.")
+		if(EMSCRIPTEN)
+			set(EMSCRIPTEN_EXE_FLAGS "${EMSCRIPTEN_EXE_FLAGS} -sMAX_WEBGL_VERSION=2")
+		else()
+			find_package(OpenGL REQUIRED)
+			target_include_directories(shell PRIVATE ${OPENGL_INCLUDE_DIR})
+			target_link_libraries(shell PRIVATE ${OPENGL_LIBRARIES} ${CMAKE_DL_LIBS})
+			target_compile_definitions(shell PRIVATE RMLUI_RENDERER_GL3)
+			if(APPLE)
+				target_compile_definitions(shell PRIVATE GL_SILENCE_DEPRECATION)
+			endif()
+		endif()
+	endif()
 endif()
 
 
@@ -690,6 +787,13 @@ if(BUILD_SAMPLES)
 	set(samples treeview customlog drag loaddocument transform bitmapfont animation benchmark demo databinding)
 	set(tutorials template datagrid datagrid_tree drag)
 
+	if(ENABLE_LOTTIE_PLUGIN)
+		list(APPEND samples "lottie")
+	endif()
+	if(ENABLE_SVG_PLUGIN)
+		list(APPEND samples "svg")
+	endif()
+
 	# Build and install the basic samples
 	foreach(sample ${samples})
 		bl_sample(${sample} ${sample_LIBRARIES})
@@ -700,98 +804,6 @@ if(BUILD_SAMPLES)
 			RUNTIME DESTINATION ${SAMPLES_DIR}/${sample}
 			BUNDLE DESTINATION ${SAMPLES_DIR})
 	endforeach()
-	
-	message("-- Can SDL2 samples be built")
-	find_package(SDL2)
-	if(SDL2_FOUND)
-		find_package(SDL2_image)
-		if(SDL2_IMAGE_FOUND)
-			find_package(GLEW)
-			if(GLEW_FOUND)
-				message("-- Can SDL2 sample w/OpenGL renderer be built - yes")
-				include_directories(${SDL2_INCLUDE_DIR} ${SDL2_IMAGE_INCLUDE_DIR} ${GLEW_INCLUDE_DIR})
-
-				bl_sample(sdl2 ${sample_LIBRARIES}  ${SDL2_LIBRARY} ${SDL2_IMAGE_LIBRARY} ${GLEW_LIBRARIES})
-			
-				# The samples always set this as their current working directory
-				install(DIRECTORY DESTINATION ${SAMPLES_DIR}/basic/sdl2)
-				install(TARGETS sdl2
-					RUNTIME DESTINATION ${SAMPLES_DIR}/sdl2
-					BUNDLE DESTINATION ${SAMPLES_DIR})
-			else()
-					message("-- Can SDL2 sample w/OpenGL renderer be built - no - GLEW not found")
-			endif()
-			
-			if("${SDL2_VERSION}" VERSION_GREATER_EQUAL "2.0.20")
-				message("-- Can SDL2 sample w/SDL-renderer be built - yes")
-				include_directories(${SDL2_INCLUDE_DIR} ${SDL2_IMAGE_INCLUDE_DIR})
-
-				bl_sample(sdl2_sdlrenderer ${sample_LIBRARIES} ${SDL2_LIBRARY} ${SDL2_IMAGE_LIBRARY})
-			
-				install(DIRECTORY DESTINATION ${SAMPLES_DIR}/basic/sdl2_sdlrenderer)
-				install(TARGETS sdl2_sdlrenderer
-					RUNTIME DESTINATION ${SAMPLES_DIR}/sdl2_sdlrenderer
-					BUNDLE DESTINATION ${SAMPLES_DIR})
-			else()
-				message("-- Can SDL2 sample w/SDL-renderer be built - no - requires SDL 2.0.20 (found ${SDL2_VERSION})")
-			endif()
-		else()
-				message("-- Can SDL2 samples be built - SDL2_image not found")
-		endif()
-	else()
-		message("-- Can SDL2 samples be built - SDL2 not found")
-	endif()
-
-
-	message("-- Can SFML 2.x sample be built")
-	if (WIN32)
-		find_package(SFML 2 COMPONENTS graphics window system main)
-	else()
-		find_package(SFML 2 COMPONENTS graphics window system)
-	endif()
-	if(NOT SFML_FOUND)
-		message("-- Can SFML 2.x sample be built - no")
-	else()
-		find_package(GLEW)
-		if(GLEW_FOUND)
-			message("-- Can SFML 2.x sample be built - yes: with GLEW")
-			include_directories(${SFML_INCLUDE_DIR} ${GLEW_INCLUDE_DIR})
-			add_definitions( -DENABLE_GLEW )
-			bl_sample(sfml2 ${sample_LIBRARIES} ${SFML_LIBRARIES} ${GLEW_LIBRARIES})
-		else()
-			message("-- Can SFML 2.x sample be built - yes: without GLEW")
-			include_directories(${SFML_INCLUDE_DIR})
-			bl_sample(sfml2 ${sample_LIBRARIES} ${SFML_LIBRARIES})
-		endif()
-			
-			# The samples always set this as their current working directory
-			install(DIRECTORY DESTINATION ${SAMPLES_DIR}/basic/sfml2)
-			install(TARGETS sfml2
-				RUNTIME DESTINATION ${SAMPLES_DIR}/sfml2
-				BUNDLE DESTINATION ${SAMPLES_DIR})
-	endif()
-	
-	if( ENABLE_LOTTIE_PLUGIN )
-		bl_sample(lottie ${sample_LIBRARIES})
-		
-		# The samples always set this as their current working directory
-		install(DIRECTORY DESTINATION ${SAMPLES_DIR}/basic/lottie)
-		install(TARGETS lottie
-			RUNTIME DESTINATION ${SAMPLES_DIR}/lottie
-			BUNDLE DESTINATION ${SAMPLES_DIR}
-		)
-	endif()
-	
-	if( ENABLE_SVG_PLUGIN )
-		bl_sample(svg ${sample_LIBRARIES})
-		
-		# The samples always set this as their current working directory
-		install(DIRECTORY DESTINATION ${SAMPLES_DIR}/basic/svg)
-		install(TARGETS svg
-			RUNTIME DESTINATION ${SAMPLES_DIR}/svg
-			BUNDLE DESTINATION ${SAMPLES_DIR}
-		)
-	endif()
 
 	# Build and install the tutorials
 	foreach(tutorial ${tutorials})
@@ -819,6 +831,49 @@ if(BUILD_SAMPLES)
 			RUNTIME DESTINATION ${SAMPLES_DIR}/luainvaders
 			BUNDLE DESTINATION ${SAMPLES_DIR})
 	endif()
+	
+	# Add assets to emscripten binaries
+	if(EMSCRIPTEN)
+		message("-- Preloading emscipten sample assets")
+		
+		set(COMMON_ASSET_FOLDER "Samples/assets/")
+		set(EMSCRIPTEN_EXE_FLAGS "${EMSCRIPTEN_EXE_FLAGS} --preload-file ${CMAKE_CURRENT_SOURCE_DIR}/${COMMON_ASSET_FOLDER}@/${COMMON_ASSET_FOLDER}")
+
+		foreach(sample ${samples})
+			set(SAMPLE_DATA_FOLDER "Samples/basic/${sample}/data/")
+			set(ABS_SAMPLE_DATA_FOLDER "${CMAKE_CURRENT_SOURCE_DIR}/${SAMPLE_DATA_FOLDER}")
+			if(EXISTS ${ABS_SAMPLE_DATA_FOLDER})
+				target_link_libraries(${sample} "--preload-file ${ABS_SAMPLE_DATA_FOLDER}@/${SAMPLE_DATA_FOLDER}")
+			endif()
+		endforeach()
+		
+		foreach(tutorial ${tutorials})
+			set(TUTORIAL_DATA_FOLDER "Samples/tutorial/${tutorial}/data/")
+			set(ABS_TUTORIAL_DATA_FOLDER "${CMAKE_CURRENT_SOURCE_DIR}/${TUTORIAL_DATA_FOLDER}")
+			if(EXISTS ${ABS_TUTORIAL_DATA_FOLDER})
+				target_link_libraries("tutorial_${tutorial}" "--preload-file ${ABS_TUTORIAL_DATA_FOLDER}@/${TUTORIAL_DATA_FOLDER}")
+			endif()
+		endforeach()
+		
+		set(INVADER_DATA_FOLDER "Samples/invaders/data/")
+		target_link_libraries(invaders "-sALLOW_MEMORY_GROWTH --preload-file ${CMAKE_CURRENT_SOURCE_DIR}/${INVADER_DATA_FOLDER}@/${INVADER_DATA_FOLDER}")
+	endif()
+endif()
+
+#===================================
+# Add global options ===============
+#===================================
+
+if(EMSCRIPTEN)
+	# Enables Asyncify which we only need since the backend doesn't control the main loop. This enables us to yield to the browser during the backend call to
+	# Backend::ProcessEvents(). Asyncify results in larger and slower code, users are instead encouraged to use 'emscripten_set_main_loop()' and family.
+	set(EMSCRIPTEN_EXE_FLAGS "${EMSCRIPTEN_EXE_FLAGS} -sASYNCIFY")
+	
+	message(STATUS "Compiling for Emscripten.\n\t- Flags:${EMSCRIPTEN_FLAGS}\n\t- ExeFlags:${EMSCRIPTEN_EXE_FLAGS}")
+	set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${EMSCRIPTEN_FLAGS}")
+	set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${EMSCRIPTEN_FLAGS}")
+	set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${EMSCRIPTEN_FLAGS} ${EMSCRIPTEN_EXE_FLAGS}")
+	set(CMAKE_EXECUTABLE_SUFFIX .html)
 endif()
 
 #===================================
@@ -826,7 +881,7 @@ endif()
 #===================================
 
 if(RMLUI_TESTS_ENABLED)
-    add_subdirectory(Tests)
+	add_subdirectory(Tests)
 endif()
 
 #===================================

+ 3 - 1
Include/RmlUi/Core/Debug.h

@@ -47,7 +47,9 @@
 		#define RMLUI_BREAK
 	#endif
 #elif defined (RMLUI_PLATFORM_MACOSX)
-	#define RMLUI_BREAK {__builtin_trap();} // namespace Rml
+	#define RMLUI_BREAK {__builtin_trap();}
+#else
+	#define RMLUI_BREAK
 #endif
 
 

+ 2 - 2
Include/RmlUi/Core/Input.h

@@ -39,7 +39,7 @@ namespace Rml {
 
 namespace Input
 {
-	enum KeyIdentifier
+	enum KeyIdentifier : unsigned char
 	{
 		KI_UNKNOWN = 0,
 
@@ -257,7 +257,7 @@ namespace Input
 		KI_RMETA = 176
 	};
 
-	enum KeyModifier
+	enum KeyModifier : unsigned char
 	{
 		KM_CTRL = 1 << 0,		// Set if at least one Ctrl key is depressed.
 		KM_SHIFT = 1 << 1,		// Set if at least one Shift key is depressed.

+ 4 - 0
Include/RmlUi/Core/Platform.h

@@ -36,6 +36,10 @@
 	#define RMLUI_PLATFORM_UNIX
 	#define RMLUI_PLATFORM_MACOSX
 	#define RMLUI_PLATFORM_NAME "macosx"
+#elif defined __EMSCRIPTEN__
+	#define RMLUI_PLATFORM_UNIX
+	#define RMLUI_PLATFORM_EMSCRIPTEN
+	#define RMLUI_PLATFORM_NAME "emscripten"
 #else
 	#define RMLUI_PLATFORM_UNIX
 	#define RMLUI_PLATFORM_LINUX

+ 0 - 1
Include/RmlUi/Core/TypeConverter.h

@@ -35,7 +35,6 @@
 #include "StringUtilities.h"
 #include <stdlib.h>
 #include <stdio.h>
-#include <cinttypes>
 
 namespace Rml {
 

+ 120 - 104
Include/RmlUi/Core/TypeConverter.inl

@@ -78,8 +78,10 @@ public: \
 /////////////////////////////////////////////////
 PASS_THROUGH(int);
 PASS_THROUGH(unsigned int);
-PASS_THROUGH(int64_t);
-PASS_THROUGH(uint64_t);
+PASS_THROUGH(long);
+PASS_THROUGH(unsigned long);
+PASS_THROUGH(long long);
+PASS_THROUGH(unsigned long long);
 PASS_THROUGH(float);
 PASS_THROUGH(double);
 PASS_THROUGH(bool);
@@ -107,49 +109,82 @@ PASS_THROUGH(voidPtr);
 /////////////////////////////////////////////////
 BASIC_CONVERTER(bool, int);
 BASIC_CONVERTER(bool, unsigned int);
-BASIC_CONVERTER(bool, int64_t);
-BASIC_CONVERTER(bool, uint64_t);
+BASIC_CONVERTER(bool, long);
+BASIC_CONVERTER(bool, unsigned long);
+BASIC_CONVERTER(bool, long long);
+BASIC_CONVERTER(bool, unsigned long long);
 BASIC_CONVERTER(bool, float);
 BASIC_CONVERTER(bool, double);
 
 BASIC_CONVERTER_BOOL(int, bool);
 BASIC_CONVERTER(int, unsigned int);
-BASIC_CONVERTER(int, int64_t);
-BASIC_CONVERTER(int, uint64_t);
+BASIC_CONVERTER(int, long);
+BASIC_CONVERTER(int, unsigned long);
+BASIC_CONVERTER(int, long long);
+BASIC_CONVERTER(int, unsigned long long);
 BASIC_CONVERTER(int, float);
 BASIC_CONVERTER(int, double);
 
 BASIC_CONVERTER_BOOL(unsigned int, bool);
 BASIC_CONVERTER(unsigned int, int);
-BASIC_CONVERTER(unsigned int, int64_t);
-BASIC_CONVERTER(unsigned int, uint64_t);
+BASIC_CONVERTER(unsigned int, long);
+BASIC_CONVERTER(unsigned int, unsigned long);
+BASIC_CONVERTER(unsigned int, long long);
+BASIC_CONVERTER(unsigned int, unsigned long long);
 BASIC_CONVERTER(unsigned int, float);
 BASIC_CONVERTER(unsigned int, double);
 
-BASIC_CONVERTER_BOOL(int64_t, bool);
-BASIC_CONVERTER(int64_t, int);
-BASIC_CONVERTER(int64_t, float);
-BASIC_CONVERTER(int64_t, double);
-BASIC_CONVERTER(int64_t, unsigned int);
-
-BASIC_CONVERTER_BOOL(uint64_t, bool);
-BASIC_CONVERTER(uint64_t, int);
-BASIC_CONVERTER(uint64_t, float);
-BASIC_CONVERTER(uint64_t, double);
-BASIC_CONVERTER(uint64_t, unsigned int);
-BASIC_CONVERTER(uint64_t, int64_t);
+BASIC_CONVERTER_BOOL(long, bool);
+BASIC_CONVERTER(long, int);
+BASIC_CONVERTER(long, unsigned int);
+BASIC_CONVERTER(long, unsigned long);
+BASIC_CONVERTER(long, long long);
+BASIC_CONVERTER(long, unsigned long long);
+BASIC_CONVERTER(long, float);
+BASIC_CONVERTER(long, double);
+
+BASIC_CONVERTER_BOOL(unsigned long, bool);
+BASIC_CONVERTER(unsigned long, int);
+BASIC_CONVERTER(unsigned long, unsigned int);
+BASIC_CONVERTER(unsigned long, long);
+BASIC_CONVERTER(unsigned long, long long);
+BASIC_CONVERTER(unsigned long, unsigned long long);
+BASIC_CONVERTER(unsigned long, float);
+BASIC_CONVERTER(unsigned long, double);
+
+BASIC_CONVERTER_BOOL(long long, bool);
+BASIC_CONVERTER(long long, int);
+BASIC_CONVERTER(long long, unsigned int);
+BASIC_CONVERTER(long long, long);
+BASIC_CONVERTER(long long, unsigned long);
+BASIC_CONVERTER(long long, unsigned long long);
+BASIC_CONVERTER(long long, float);
+BASIC_CONVERTER(long long, double);
+
+BASIC_CONVERTER_BOOL(unsigned long long, bool);
+BASIC_CONVERTER(unsigned long long, int);
+BASIC_CONVERTER(unsigned long long, unsigned int);
+BASIC_CONVERTER(unsigned long long, long);
+BASIC_CONVERTER(unsigned long long, unsigned long);
+BASIC_CONVERTER(unsigned long long, long long);
+BASIC_CONVERTER(unsigned long long, float);
+BASIC_CONVERTER(unsigned long long, double);
 
 BASIC_CONVERTER_BOOL(float, bool);
 BASIC_CONVERTER(float, int);
-BASIC_CONVERTER(float, int64_t);
-BASIC_CONVERTER(float, uint64_t);
+BASIC_CONVERTER(float, long);
+BASIC_CONVERTER(float, unsigned long);
+BASIC_CONVERTER(float, long long);
+BASIC_CONVERTER(float, unsigned long long);
 BASIC_CONVERTER(float, double);
 BASIC_CONVERTER(float, unsigned int);
 
 BASIC_CONVERTER_BOOL(double, bool);
 BASIC_CONVERTER(double, int);
-BASIC_CONVERTER(double, int64_t);
-BASIC_CONVERTER(double, uint64_t);
+BASIC_CONVERTER(double, long);
+BASIC_CONVERTER(double, unsigned long);
+BASIC_CONVERTER(double, long long);
+BASIC_CONVERTER(double, unsigned long long);
 BASIC_CONVERTER(double, float);
 BASIC_CONVERTER(double, unsigned int);
 
@@ -173,59 +208,50 @@ public: \
 STRING_FLOAT_CONVERTER(float);
 STRING_FLOAT_CONVERTER(double);
 
-template<>
-class TypeConverter< String, int >
-{
+template <>
+class TypeConverter<String, int> {
 public:
-	static bool Convert(const String& src, int& dest)
-	{
-		return sscanf(src.c_str(), "%d", &dest) == 1;
-	}
+	static bool Convert(const String& src, int& dest) { return sscanf(src.c_str(), "%d", &dest) == 1; }
 };
 
-template<>
-class TypeConverter< String, unsigned int >
-{
+template <>
+class TypeConverter<String, unsigned int> {
 public:
-	static bool Convert(const String& src, unsigned int& dest)
-	{
-		return sscanf(src.c_str(), "%u", &dest) == 1;
-	}
+	static bool Convert(const String& src, unsigned int& dest) { return sscanf(src.c_str(), "%u", &dest) == 1; }
 };
 
-template<>
-class TypeConverter< String, uint64_t >
-{
+template <>
+class TypeConverter<String, long> {
 public:
-	static bool Convert(const String& src, uint64_t& dest)
-	{
-		return sscanf(src.c_str(), "%" SCNu64, &dest) == 1;
-	}
+	static bool Convert(const String& src, long& dest) { return sscanf(src.c_str(), "%ld", &dest) == 1; }
 };
 
-template<>
-class TypeConverter< String, int64_t >
-{
+template <>
+class TypeConverter<String, unsigned long> {
 public:
-	static bool Convert(const String& src, int64_t& dest)
-	{
-		return sscanf(src.c_str(), "%" SCNd64, &dest) == 1;
-	}
+	static bool Convert(const String& src, unsigned long& dest) { return sscanf(src.c_str(), "%lu", &dest) == 1; }
 };
 
-template<>
-class TypeConverter< String, byte >
-{
+template <>
+class TypeConverter<String, long long> {
 public:
-	static bool Convert(const String& src, byte& dest)
-	{
-		return sscanf(src.c_str(), "%hhu", &dest) == 1;
-	}
+	static bool Convert(const String& src, long long& dest) { return sscanf(src.c_str(), "%lld", &dest) == 1; }
 };
 
-template<>
-class TypeConverter< String, bool >
-{
+template <>
+class TypeConverter<String, unsigned long long> {
+public:
+	static bool Convert(const String& src, unsigned long long& dest) { return sscanf(src.c_str(), "%llu", &dest) == 1; }
+};
+
+template <>
+class TypeConverter<String, byte> {
+public:
+	static bool Convert(const String& src, byte& dest) { return sscanf(src.c_str(), "%hhu", &dest) == 1; }
+};
+
+template <>
+class TypeConverter<String, bool> {
 public:
 	static bool Convert(const String& src, bool& dest)
 	{
@@ -303,59 +329,50 @@ public: \
 FLOAT_STRING_CONVERTER(float);
 FLOAT_STRING_CONVERTER(double);
 
-template<>
-class TypeConverter< int, String >
-{
+template <>
+class TypeConverter<int, String> {
 public:
-	static bool Convert(const int& src, String& dest)
-	{
-		return FormatString(dest, 32, "%d", src) > 0;
-	}
+	static bool Convert(const int& src, String& dest) { return FormatString(dest, 32, "%d", src) > 0; }
 };
 
-template<>
-class TypeConverter< unsigned int, String >
-{
+template <>
+class TypeConverter<unsigned int, String> {
 public:
-	static bool Convert(const unsigned int& src, String& dest)
-	{
-		return FormatString(dest, 32, "%u", src) > 0;
-	}
+	static bool Convert(const unsigned int& src, String& dest) { return FormatString(dest, 32, "%u", src) > 0; }
 };
 
-template<>
-class TypeConverter< int64_t, String >
-{
+template <>
+class TypeConverter<long, String> {
 public:
-	static bool Convert(const int64_t& src, String& dest)
-	{
-		return FormatString(dest, 32, "%" PRId64, src) > 0;
-	}
+	static bool Convert(const long& src, String& dest) { return FormatString(dest, 32, "%ld", src) > 0; }
 };
 
-template<>
-class TypeConverter< uint64_t, String >
-{
+template <>
+class TypeConverter<unsigned long, String> {
 public:
-	static bool Convert(const uint64_t& src, String& dest)
-	{
-		return FormatString(dest, 32, "%" PRIu64, src) > 0;
-	}
+	static bool Convert(const unsigned long& src, String& dest) { return FormatString(dest, 32, "%lu", src) > 0; }
 };
 
-template<>
-class TypeConverter< byte, String >
-{
+template <>
+class TypeConverter<long long, String> {
 public:
-	static bool Convert(const byte& src, String& dest)
-	{
-		return FormatString(dest, 32, "%hhu", src) > 0;
-	}
+	static bool Convert(const long long& src, String& dest) { return FormatString(dest, 32, "%lld", src) > 0; }
 };
 
-template<>
-class TypeConverter< bool, String >
-{
+template <>
+class TypeConverter<unsigned long long, String> {
+public:
+	static bool Convert(const unsigned long long& src, String& dest) { return FormatString(dest, 32, "%llu", src) > 0; }
+};
+
+template <>
+class TypeConverter<byte, String> {
+public:
+	static bool Convert(const byte& src, String& dest) { return FormatString(dest, 32, "%hhu", src) > 0; }
+};
+
+template <>
+class TypeConverter<bool, String> {
 public:
 	static bool Convert(const bool& src, String& dest)
 	{
@@ -364,11 +381,10 @@ public:
 	}
 };
 
-template<>
-class TypeConverter< char*, String >
-{
+template <>
+class TypeConverter<char*, String> {
 public:
-	static bool Convert(char* const & src, String& dest)
+	static bool Convert(char* const& src, String& dest)
 	{
 		dest = src;
 		return true;

+ 9 - 6
Samples/assets/invader.rcss

@@ -159,16 +159,17 @@ div#title_bar
 	z-index: 1;
 
 	position: absolute;
-	top: 3dp;
+	top: 7dp;
 	left: 0;
 	
 	text-align: left;
+	vertical-align: bottom;
 }
 
 div#title_bar div#icon
 {
 	position: absolute;
-	left: 20dp;
+	left: 15dp;
 	top: -4dp;
 	
 	width: 51dp;
@@ -180,14 +181,16 @@ div#title_bar span
 {
 	padding-left: 85dp;
 	padding-right: 25dp;
-	padding-top: 23dp;
-	padding-bottom: 51dp;
-
+	padding-top: 18dp;
+	padding-bottom: 43dp;
+	
+	vertical-align: top;
+	
+	line-height: 24dp;
 	font-size: 20dp;
 	font-weight: bold;
 	
 	font-effect: glow(1dp black);
-
 	decorator: tiled-horizontal( title-bar-l, title-bar-c, title-bar-r );
 }
 

+ 74 - 109
Samples/basic/animation/src/main.cpp

@@ -27,17 +27,13 @@
  */
 
 #include <RmlUi/Core.h>
+#include <RmlUi/Core/TransformPrimitive.h>
 #include <RmlUi/Debugger.h>
-#include <Input.h>
+#include <RmlUi_Backend.h>
 #include <Shell.h>
-#include <ShellRenderInterfaceOpenGL.h>
-#include <RmlUi/Core/TransformPrimitive.h>
-
 #include <sstream>
 
-
-class DemoWindow
-{
+class DemoWindow {
 public:
 	DemoWindow(const Rml::String &title, Rml::Context *context)
 	{
@@ -157,62 +153,11 @@ private:
 	double t_prev_fade = 0;
 };
 
-
 Rml::Context* context = nullptr;
-ShellRenderInterfaceExtensions *shell_renderer;
-DemoWindow* window = nullptr;
-
 bool run_loop = true;
 bool single_loop = false;
 int nudge = 0;
 
-void GameLoop()
-{
-	double t = Shell::GetElapsedTime();
-
-	if(run_loop || single_loop)
-	{
-		if (window)
-			window->Update(t);
-
-		context->Update();
-
-		shell_renderer->PrepareRenderBuffer();
-		context->Render();
-		shell_renderer->PresentRenderBuffer();
-
-		single_loop = false;
-	}
-
-	static double t_prev = 0.0f;
-	float dt = float(t - t_prev);
-	static int count_frames = 0;
-	count_frames += 1;
-
-	if(nudge)
-	{
-		t_prev = t;
-		static float ff = 0.0f;
-		ff += float(nudge)*0.3f;
-		auto el = window->GetDocument()->GetElementById("exit");
-		el->SetProperty(Rml::PropertyId::MarginLeft, Rml::Property(ff, Rml::Property::PX));
-		float f_left = el->GetAbsoluteLeft();
-		Rml::Log::Message(Rml::Log::LT_INFO, "margin-left: '%f'   abs: %f.", ff, f_left);
-		nudge = 0;
-	}
-
-	if (window && dt > 0.2f)
-	{
-		t_prev = t;
-		auto el = window->GetDocument()->GetElementById("fps");
-		float fps = float(count_frames) / dt;
-		count_frames = 0;
-		el->SetInnerRML(Rml::CreateString( 20, "FPS: %f", fps ));
-	}
-}
-
-
-
 class Event : public Rml::EventListener
 {
 public:
@@ -222,8 +167,8 @@ public:
 	{
 		using namespace Rml;
 
-		if(value == "exit")
-			Shell::RequestExit();
+		if (value == "exit")
+			Backend::RequestExit();
 
 		switch (event.GetId())
 		{
@@ -250,7 +195,7 @@ public:
 			}
 			else if (key_identifier == Rml::Input::KI_ESCAPE)
 			{
-				Shell::RequestExit();
+				Backend::RequestExit();
 			}
 			else if (key_identifier == Rml::Input::KI_LEFT)
 			{
@@ -308,92 +253,112 @@ private:
 	Rml::String value;
 };
 
-
-class EventInstancer : public Rml::EventListenerInstancer
-{
+class EventInstancer : public Rml::EventListenerInstancer {
 public:
-
-	/// Instances a new event handle for Invaders.
-	Rml::EventListener* InstanceEventListener(const Rml::String& value, Rml::Element* /*element*/) override
-	{
-		return new Event(value);
-	}
+	Rml::EventListener* InstanceEventListener(const Rml::String& value, Rml::Element* /*element*/) override { return new Event(value); }
 };
 
-
 #if defined RMLUI_PLATFORM_WIN32
-#include <windows.h>
-int APIENTRY WinMain(HINSTANCE RMLUI_UNUSED_PARAMETER(instance_handle), HINSTANCE RMLUI_UNUSED_PARAMETER(previous_instance_handle), char* RMLUI_UNUSED_PARAMETER(command_line), int RMLUI_UNUSED_PARAMETER(command_show))
+	#include <RmlUi_Include_Windows.h>
+int APIENTRY WinMain(HINSTANCE /*instance_handle*/, HINSTANCE /*previous_instance_handle*/, char* /*command_line*/, int /*command_show*/)
 #else
-int main(int RMLUI_UNUSED_PARAMETER(argc), char** RMLUI_UNUSED_PARAMETER(argv))
+int main(int /*argc*/, char** /*argv*/)
 #endif
 {
-#ifdef RMLUI_PLATFORM_WIN32
-	RMLUI_UNUSED(instance_handle);
-	RMLUI_UNUSED(previous_instance_handle);
-	RMLUI_UNUSED(command_line);
-	RMLUI_UNUSED(command_show);
-#else
-	RMLUI_UNUSED(argc);
-	RMLUI_UNUSED(argv);
-#endif
-
-	const int width = 1700;
-	const int height = 900;
+	const int window_width = 1700;
+	const int window_height = 900;
 
+	// Initializes the shell which provides common functionality used by the included samples.
+	if (!Shell::Initialize())
+		return -1;
 
-	ShellRenderInterfaceOpenGL opengl_renderer;
-	shell_renderer = &opengl_renderer;
-
-	// Generic OS initialisation, creates a window and attaches OpenGL.
-	if (!Shell::Initialise() ||
-		!Shell::OpenWindow("Animation Sample", shell_renderer, width, height, true))
+	// Constructs the system and render interfaces, creates a window, and attaches the renderer.
+	if (!Backend::Initialize("Animation Sample", window_width, window_height, true))
 	{
 		Shell::Shutdown();
 		return -1;
 	}
 
-	// RmlUi initialisation.
-	Rml::SetRenderInterface(&opengl_renderer);
-	opengl_renderer.SetViewport(width, height);
-
-	ShellSystemInterface system_interface;
-	Rml::SetSystemInterface(&system_interface);
+	// Install the custom interfaces constructed by the backend before initializing RmlUi.
+	Rml::SetSystemInterface(Backend::GetSystemInterface());
+	Rml::SetRenderInterface(Backend::GetRenderInterface());
 
+	// RmlUi initialisation.
 	Rml::Initialise();
 
-	// Create the main RmlUi context and set it on the shell's input layer.
-	context = Rml::CreateContext("main", Rml::Vector2i(width, height));
-	if (context == nullptr)
+	// Create the main RmlUi context.
+	context = Rml::CreateContext("main", Rml::Vector2i(window_width, window_height));
+	if (!context)
 	{
 		Rml::Shutdown();
+		Backend::Shutdown();
 		Shell::Shutdown();
 		return -1;
 	}
 
 	Rml::Debugger::Initialise(context);
-	Input::SetContext(context);
-	Shell::SetContext(context);
 
 	EventInstancer event_listener_instancer;
 	Rml::Factory::RegisterEventListenerInstancer(&event_listener_instancer);
 
-	Shell::LoadFonts("assets/");
+	Shell::LoadFonts();
 
-	window = new DemoWindow("Animation sample", context);
+	Rml::UniquePtr<DemoWindow> window = Rml::MakeUnique<DemoWindow>("Animation sample", context);
 	window->GetDocument()->AddEventListener(Rml::EventId::Keydown, new Event("hello"));
 	window->GetDocument()->AddEventListener(Rml::EventId::Keyup, new Event("hello"));
 	window->GetDocument()->AddEventListener(Rml::EventId::Animationend, new Event("hello"));
 
+	bool running = true;
+	while (running)
+	{
+		running = Backend::ProcessEvents(context, &Shell::ProcessKeyDownShortcuts);
+
+		double t = Rml::GetSystemInterface()->GetElapsedTime();
 
-	Shell::EventLoop(GameLoop);
+		if (run_loop || single_loop)
+		{
+			window->Update(t);
+			context->Update();
+
+			Backend::BeginFrame();
+			context->Render();
+			Backend::PresentFrame();
+
+			single_loop = false;
+		}
+
+		static double t_prev = 0.0f;
+		float dt = float(t - t_prev);
+		static int count_frames = 0;
+		count_frames += 1;
+
+		if (nudge)
+		{
+			t_prev = t;
+			static float ff = 0.0f;
+			ff += float(nudge) * 0.3f;
+			auto el = window->GetDocument()->GetElementById("exit");
+			el->SetProperty(Rml::PropertyId::MarginLeft, Rml::Property(ff, Rml::Property::PX));
+			float f_left = el->GetAbsoluteLeft();
+			Rml::Log::Message(Rml::Log::LT_INFO, "margin-left: '%f'   abs: %f.", ff, f_left);
+			nudge = 0;
+		}
 
-	delete window;
+		if (dt > 0.2f)
+		{
+			t_prev = t;
+			auto el = window->GetDocument()->GetElementById("fps");
+			float fps = float(count_frames) / dt;
+			count_frames = 0;
+			el->SetInnerRML(Rml::CreateString(20, "FPS: %f", fps));
+		}
+	}
+
+	window.reset();
 
 	// Shutdown RmlUi.
 	Rml::Shutdown();
-
-	Shell::CloseWindow();
+	Backend::Shutdown();
 	Shell::Shutdown();
 
 	return 0;

+ 74 - 98
Samples/basic/benchmark/src/main.cpp

@@ -28,10 +28,8 @@
 
 #include <RmlUi/Core.h>
 #include <RmlUi/Debugger.h>
-#include <Input.h>
+#include <RmlUi_Backend.h>
 #include <Shell.h>
-#include <ShellRenderInterfaceOpenGL.h>
-
 
 class DemoWindow
 {
@@ -116,66 +114,11 @@ private:
 	Rml::ElementDocument *document;
 };
 
-
-Rml::Context* context = nullptr;
-ShellRenderInterfaceExtensions *shell_renderer;
-DemoWindow* window = nullptr;
-
 bool run_loop = true;
 bool single_loop = true;
 bool run_update = true;
 bool single_update = true;
 
-void GameLoop()
-{
-	if (run_update || single_update)
-	{
-		single_update = false;
-
-		window->performance_test();
-	}
-
-	if (run_loop || single_loop)
-	{
-		single_loop = false;
-	
-		context->Update();
-
-		shell_renderer->PrepareRenderBuffer();
-		context->Render();
-		shell_renderer->PresentRenderBuffer();
-	}
-
-	static constexpr int buffer_size = 200;
-	static float fps_buffer[buffer_size] = {};
-	static int buffer_index = 0;
-
-	static double t_prev = 0.0f;
-	double t = Shell::GetElapsedTime();
-	float dt = float(t - t_prev);
-	t_prev = t;
-	static int count_frames = 0;
-	count_frames += 1;
-
-	float fps = 1.0f / dt;
-	fps_buffer[buffer_index] = fps;
-	buffer_index = ((buffer_index + 1) % buffer_size);
-
-	if (window && count_frames > buffer_size / 8)
-	{
-		float fps_mean = 0;
-		for (int i = 0; i < buffer_size; i++)
-			fps_mean += fps_buffer[(buffer_index + i) % buffer_size];
-		fps_mean = fps_mean / (float)buffer_size;
-
-		auto el = window->GetDocument()->GetElementById("fps");
-		count_frames = 0;
-		el->SetInnerRML(Rml::CreateString(20, "FPS: %f", fps_mean));
-	}
-}
-
-
-
 class Event : public Rml::EventListener
 {
 public:
@@ -186,7 +129,7 @@ public:
 		using namespace Rml;
 
 		if(value == "exit")
-			Shell::RequestExit();
+			Backend::RequestExit();
 
 		if (event == "keydown")
 		{
@@ -212,7 +155,7 @@ public:
 			}
 			else if (key_identifier == Rml::Input::KI_ESCAPE)
 			{
-				Shell::RequestExit();
+				Backend::RequestExit();
 			}
 		}
 	}
@@ -223,7 +166,6 @@ private:
 	Rml::String value;
 };
 
-
 class EventInstancer : public Rml::EventListenerInstancer
 {
 public:
@@ -235,79 +177,113 @@ public:
 	}
 };
 
-
 #if defined RMLUI_PLATFORM_WIN32
-#include <windows.h>
-int APIENTRY WinMain(HINSTANCE RMLUI_UNUSED_PARAMETER(instance_handle), HINSTANCE RMLUI_UNUSED_PARAMETER(previous_instance_handle), char* RMLUI_UNUSED_PARAMETER(command_line), int RMLUI_UNUSED_PARAMETER(command_show))
+	#include <RmlUi_Include_Windows.h>
+int APIENTRY WinMain(HINSTANCE /*instance_handle*/, HINSTANCE /*previous_instance_handle*/, char* /*command_line*/, int /*command_show*/)
 #else
-int main(int RMLUI_UNUSED_PARAMETER(argc), char** RMLUI_UNUSED_PARAMETER(argv))
+int main(int /*argc*/, char** /*argv*/)
 #endif
 {
-#ifdef RMLUI_PLATFORM_WIN32
-	RMLUI_UNUSED(instance_handle);
-	RMLUI_UNUSED(previous_instance_handle);
-	RMLUI_UNUSED(command_line);
-	RMLUI_UNUSED(command_show);
-#else
-	RMLUI_UNUSED(argc);
-	RMLUI_UNUSED(argv);
-#endif
-
-	const int width = 1800;
-	const int height = 1000;
+	const int window_width = 1800;
+	const int window_height = 1000;
 
-	ShellRenderInterfaceOpenGL opengl_renderer;
-	shell_renderer = &opengl_renderer;
+	// Initializes the shell which provides common functionality used by the included samples.
+	if (!Shell::Initialize())
+		return -1;
 
-	// Generic OS initialisation, creates a window and attaches OpenGL.
-	if (!Shell::Initialise() ||
-		!Shell::OpenWindow("Benchmark Sample", shell_renderer, width, height, true))
+	// Constructs the system and render interfaces, creates a window, and attaches the renderer.
+	if (!Backend::Initialize("Benchmark Sample", window_width, window_height, true))
 	{
 		Shell::Shutdown();
 		return -1;
 	}
 
-	// RmlUi initialisation.
-	Rml::SetRenderInterface(&opengl_renderer);
-	opengl_renderer.SetViewport(width, height);
-
-	ShellSystemInterface system_interface;
-	Rml::SetSystemInterface(&system_interface);
+	// Install the custom interfaces constructed by the backend before initializing RmlUi.
+	Rml::SetSystemInterface(Backend::GetSystemInterface());
+	Rml::SetRenderInterface(Backend::GetRenderInterface());
 
+	// RmlUi initialisation.
 	Rml::Initialise();
 
-	// Create the main RmlUi context and set it on the shell's input layer.
-	context = Rml::CreateContext("main", Rml::Vector2i(width, height));
-	if (context == nullptr)
+	// Create the main RmlUi context.
+	Rml::Context* context = Rml::CreateContext("main", Rml::Vector2i(window_width, window_height));
+	if (!context)
 	{
 		Rml::Shutdown();
+		Backend::Shutdown();
 		Shell::Shutdown();
 		return -1;
 	}
 
 	Rml::Debugger::Initialise(context);
-	Input::SetContext(context);
-	Shell::SetContext(context);
 
 	EventInstancer event_listener_instancer;
 	Rml::Factory::RegisterEventListenerInstancer(&event_listener_instancer);
 
-	Shell::LoadFonts("assets/");
+	Shell::LoadFonts();
 
-	window = new DemoWindow("Benchmark sample", context);
+	Rml::UniquePtr<DemoWindow> window = Rml::MakeUnique<DemoWindow>("Benchmark sample", context);
 	window->GetDocument()->AddEventListener(Rml::EventId::Keydown, new Event("hello"));
 	window->GetDocument()->AddEventListener(Rml::EventId::Keyup, new Event("hello"));
 	window->GetDocument()->AddEventListener(Rml::EventId::Animationend, new Event("hello"));
 
+	bool running = true;
+	while (running)
+	{
+		running = Backend::ProcessEvents(context, &Shell::ProcessKeyDownShortcuts);
+
+		if (run_update || single_update)
+		{
+			single_update = false;
+
+			window->performance_test();
+		}
 
-	Shell::EventLoop(GameLoop);
+		if (run_loop || single_loop)
+		{
+			single_loop = false;
+
+			context->Update();
+
+			Backend::BeginFrame();
+			context->Render();
+			Backend::PresentFrame();
+		}
+
+		static constexpr int buffer_size = 200;
+		static float fps_buffer[buffer_size] = {};
+		static int buffer_index = 0;
+
+		static double t_prev = 0.0f;
+		double t = Rml::GetSystemInterface()->GetElapsedTime();
+		float dt = float(t - t_prev);
+		t_prev = t;
+		static int count_frames = 0;
+		count_frames += 1;
+
+		float fps = 1.0f / dt;
+		fps_buffer[buffer_index] = fps;
+		buffer_index = ((buffer_index + 1) % buffer_size);
+
+		if (window && count_frames > buffer_size / 8)
+		{
+			float fps_mean = 0;
+			for (int i = 0; i < buffer_size; i++)
+				fps_mean += fps_buffer[(buffer_index + i) % buffer_size];
+			fps_mean = fps_mean / (float)buffer_size;
+
+			auto el = window->GetDocument()->GetElementById("fps");
+			count_frames = 0;
+			el->SetInnerRML(Rml::CreateString(20, "FPS: %f", fps_mean));
+		}
+	}
 
-	delete window;
+	window.reset();
 
 	// Shutdown RmlUi.
 	Rml::Shutdown();
 
-	Shell::CloseWindow();
+	Backend::Shutdown();
 	Shell::Shutdown();
 
 	return 0;

+ 37 - 55
Samples/basic/bitmapfont/src/main.cpp

@@ -26,13 +26,11 @@
  *
  */
 
+#include "FontEngineInterfaceBitmap.h"
 #include <RmlUi/Core.h>
 #include <RmlUi/Debugger.h>
-#include <Input.h>
+#include <RmlUi_Backend.h>
 #include <Shell.h>
-#include <ShellRenderInterfaceOpenGL.h>
-
-#include "FontEngineInterfaceBitmap.h"
 
 /*
 
@@ -43,84 +41,55 @@
 
 */
 
-Rml::Context* context = nullptr;
-
-ShellRenderInterfaceExtensions *shell_renderer;
-
-void GameLoop()
-{
-	context->Update();
-
-	shell_renderer->PrepareRenderBuffer();
-	context->Render();
-	shell_renderer->PresentRenderBuffer();
-}
-
 #if defined RMLUI_PLATFORM_WIN32
-#include <windows.h>
-int APIENTRY WinMain(HINSTANCE RMLUI_UNUSED_PARAMETER(instance_handle), HINSTANCE RMLUI_UNUSED_PARAMETER(previous_instance_handle), char* RMLUI_UNUSED_PARAMETER(command_line), int RMLUI_UNUSED_PARAMETER(command_show))
+	#include <RmlUi_Include_Windows.h>
+int APIENTRY WinMain(HINSTANCE /*instance_handle*/, HINSTANCE /*previous_instance_handle*/, char* /*command_line*/, int /*command_show*/)
 #else
-int main(int RMLUI_UNUSED_PARAMETER(argc), char** RMLUI_UNUSED_PARAMETER(argv))
+int main(int /*argc*/, char** /*argv*/)
 #endif
 {
-#ifdef RMLUI_PLATFORM_WIN32
-	RMLUI_UNUSED(instance_handle);
-	RMLUI_UNUSED(previous_instance_handle);
-	RMLUI_UNUSED(command_line);
-	RMLUI_UNUSED(command_show);
-#else
-	RMLUI_UNUSED(argc);
-	RMLUI_UNUSED(argv);
-#endif
-
-#ifdef RMLUI_PLATFORM_WIN32
-        AllocConsole();
-#endif
-
     int window_width = 1024;
-    int window_height = 768;
+	int window_height = 768;
 
-	ShellRenderInterfaceOpenGL opengl_renderer;
-	shell_renderer = &opengl_renderer;
+	// Initializes the shell which provides common functionality used by the included samples.
+	if (!Shell::Initialize())
+		return -1;
 
-	// Generic OS initialisation, creates a window and attaches OpenGL.
-	if (!Shell::Initialise() ||
-		!Shell::OpenWindow("Bitmap Font Sample", shell_renderer, window_width, window_height, true))
+	// Constructs the system and render interfaces, creates a window, and attaches the renderer.
+	if (!Backend::Initialize("Bitmap Font Sample", window_width, window_height, true))
 	{
 		Shell::Shutdown();
 		return -1;
 	}
 
-	// RmlUi initialisation.
-	Rml::SetRenderInterface(&opengl_renderer);
-	shell_renderer->SetViewport(window_width, window_height);
-
-	ShellSystemInterface system_interface;
-	Rml::SetSystemInterface(&system_interface);
+	// Install the custom interfaces constructed by the backend before initializing RmlUi.
+	Rml::SetSystemInterface(Backend::GetSystemInterface());
+	Rml::SetRenderInterface(Backend::GetRenderInterface());
 
 	// Construct and load the font interface.
-	FontEngineInterfaceBitmap font_interface;
-	Rml::SetFontEngineInterface(&font_interface);
+	auto font_interface = Rml::MakeUnique<FontEngineInterfaceBitmap>();
+	Rml::SetFontEngineInterface(font_interface.get());
 
+	// RmlUi initialisation.
 	Rml::Initialise();
 
-	// Create the main RmlUi context and set it on the shell's input layer.
-	context = Rml::CreateContext("main", Rml::Vector2i(window_width, window_height));
-	if (context == nullptr)
+	// Create the main RmlUi context.
+	Rml::Context* context = Rml::CreateContext("main", Rml::Vector2i(window_width, window_height));
+	if (!context)
 	{
 		Rml::Shutdown();
+		Backend::Shutdown();
 		Shell::Shutdown();
 		return -1;
 	}
 
 	Rml::Debugger::Initialise(context);
-	Input::SetContext(context);
-	Shell::SetContext(context);
 
     // Load bitmap font
 	if (!Rml::LoadFontFace("basic/bitmapfont/data/Comfortaa_Regular_22.fnt"))
 	{
 		Rml::Shutdown();
+		Backend::Shutdown();
 		Shell::Shutdown();
 		return -1;
 	}
@@ -134,12 +103,25 @@ int main(int RMLUI_UNUSED_PARAMETER(argc), char** RMLUI_UNUSED_PARAMETER(argv))
 		document->Show();
 	}
 
-	Shell::EventLoop(GameLoop);
+	bool running = true;
+	while (running)
+	{
+		running = Backend::ProcessEvents(context, &Shell::ProcessKeyDownShortcuts);
+
+		context->Update();
+
+		Backend::BeginFrame();
+		context->Render();
+		Backend::PresentFrame();
+	}
 
 	// Shutdown RmlUi.
 	Rml::Shutdown();
 
-	Shell::CloseWindow();
+	// Destroy the font interface before taking down the shell, this way font textures are properly released through the render interface.
+	font_interface.reset();
+
+	Backend::Shutdown();
 	Shell::Shutdown();
 
 	return 0;

+ 10 - 6
Samples/basic/customlog/src/SystemInterface.cpp

@@ -30,9 +30,10 @@
 #include <RmlUi/Core/Platform.h>
 #include <RmlUi/Core/StringUtilities.h>
 #include <Shell.h>
+#include <chrono>
 #include <stdio.h>
 #ifdef RMLUI_PLATFORM_WIN32
-#include <windows.h>
+#include <RmlUi_Include_Windows.h>
 #endif
 
 SystemInterface::SystemInterface()
@@ -42,19 +43,22 @@ SystemInterface::SystemInterface()
 
 SystemInterface::~SystemInterface()
 {
-	if (fp != nullptr)
+	if (fp)
 		fclose(fp);
 }
 
 // Get the number of seconds elapsed since the start of the application.
 double SystemInterface::GetElapsedTime()
 {
-	return Shell::GetElapsedTime();
+	static const auto start = std::chrono::steady_clock::now();
+	const auto current = std::chrono::steady_clock::now();
+	std::chrono::duration<double> diff = current - start;
+	return diff.count();
 }
 
 bool SystemInterface::LogMessage(Rml::Log::Type type, const Rml::String& message)
 {
-	if (fp != nullptr)
+	if (fp)
 	{
 		// Select a prefix appropriate for the severity of the message.
 		const char* prefix;
@@ -75,7 +79,7 @@ bool SystemInterface::LogMessage(Rml::Log::Type type, const Rml::String& message
 		}
 
 		// Print the message and timestamp to file, and force a write in case of a crash.
-		fprintf(fp, "%s (%.2f): %s", prefix, GetElapsedTime(), message.c_str());
+		fprintf(fp, "%s (%.2f): %s\n", prefix, GetElapsedTime(), message.c_str());
 		fflush(fp);
 
 #ifdef RMLUI_PLATFORM_WIN32
@@ -84,7 +88,7 @@ bool SystemInterface::LogMessage(Rml::Log::Type type, const Rml::String& message
 			Rml::String assert_message = Rml::CreateString(1024, "%s\nWould you like to interrupt execution?", message.c_str());
 
 			// Return TRUE if the user presses NO (continue execution)
-			return MessageBox(nullptr, assert_message.c_str(), "Assertion Failure", MB_YESNO | MB_ICONSTOP | MB_DEFBUTTON2 | MB_SYSTEMMODAL) == IDNO;
+			return MessageBoxA(nullptr, assert_message.c_str(), "Assertion Failure", MB_YESNO | MB_ICONSTOP | MB_DEFBUTTON2 | MB_SYSTEMMODAL) == IDNO;
 		}
 #endif
 	}

+ 36 - 54
Samples/basic/customlog/src/main.cpp

@@ -26,90 +26,62 @@
  *
  */
 
+#include "SystemInterface.h"
 #include <RmlUi/Core.h>
 #include <RmlUi/Debugger.h>
-#include <Input.h>
+#include <RmlUi_Backend.h>
 #include <Shell.h>
-#include <ShellRenderInterfaceOpenGL.h>
-#include "SystemInterface.h"
-
-Rml::Context* context = nullptr;
-
-ShellRenderInterfaceExtensions *shell_renderer;
-
-void GameLoop()
-{
-	context->Update();
-
-	shell_renderer->PrepareRenderBuffer();
-	context->Render();
-	shell_renderer->PresentRenderBuffer();
-}
 
 #if defined RMLUI_PLATFORM_WIN32
-#include <windows.h>
-int APIENTRY WinMain(HINSTANCE RMLUI_UNUSED_PARAMETER(instance_handle), HINSTANCE RMLUI_UNUSED_PARAMETER(previous_instance_handle), char* RMLUI_UNUSED_PARAMETER(command_line), int RMLUI_UNUSED_PARAMETER(command_show))
+	#include <RmlUi_Include_Windows.h>
+int APIENTRY WinMain(HINSTANCE /*instance_handle*/, HINSTANCE /*previous_instance_handle*/, char* /*command_line*/, int /*command_show*/)
 #else
-int main(int RMLUI_UNUSED_PARAMETER(argc), char** RMLUI_UNUSED_PARAMETER(argv))
+int main(int /*argc*/, char** /*argv*/)
 #endif
 {
-#ifdef RMLUI_PLATFORM_WIN32
-	RMLUI_UNUSED(instance_handle);
-	RMLUI_UNUSED(previous_instance_handle);
-	RMLUI_UNUSED(command_line);
-	RMLUI_UNUSED(command_show);
-#else
-	RMLUI_UNUSED(argc);
-	RMLUI_UNUSED(argv);
-#endif
-
-#ifdef RMLUI_PLATFORM_WIN32
-        AllocConsole();
-#endif
-
 	int window_width = 1024;
 	int window_height = 768;
 
-	ShellRenderInterfaceOpenGL opengl_renderer;
-	shell_renderer = &opengl_renderer;
+	// Initializes the shell which provides common functionality used by the included samples.
+	if (!Shell::Initialize())
+		return -1;
 
-	// Generic OS initialisation, creates a window and attaches OpenGL.
-	if (!Shell::Initialise() ||
-		!Shell::OpenWindow("Custom File Handler Sample", shell_renderer, window_width, window_height, true))
+	// Constructs the system and render interfaces, creates a window, and attaches the renderer.
+	if (!Backend::Initialize("Custom File Handler Sample", window_width, window_height, true))
 	{
 		Shell::Shutdown();
 		return -1;
 	}
 
-	// RmlUi initialisation.
-	Rml::SetRenderInterface(&opengl_renderer);
-	opengl_renderer.SetViewport(window_width, window_height);
+	// Install the custom interfaces constructed by the backend before initializing RmlUi.
+	Rml::SetSystemInterface(Backend::GetSystemInterface());
+	Rml::SetRenderInterface(Backend::GetRenderInterface());
+
 
-	// Initialise our system interface to write the log messages to file.
-	ShellSystemInterface system_interface;
+	// Initialize our custom system interface to write the log messages to file.
+	SystemInterface system_interface;
 	Rml::SetSystemInterface(&system_interface);
 
+	// RmlUi initialisation.
 	Rml::Initialise();
 
-	// Create the main RmlUi context and set it on the shell's input layer.
-	context = Rml::CreateContext("main", Rml::Vector2i(window_width, window_height));
-	if (context == nullptr)
+	// Create the main RmlUi context.
+	Rml::Context* context = Rml::CreateContext("main", Rml::Vector2i(window_width, window_height));
+	if (!context)
 	{
 		Rml::Shutdown();
+		Backend::Shutdown();
 		Shell::Shutdown();
 		return -1;
 	}
 
 	Rml::Debugger::Initialise(context);
-	Input::SetContext(context);
-	Shell::SetContext(context);
-
-	Shell::LoadFonts("assets/");
+	Shell::LoadFonts();
 
 	// Load a non-existent document to spawn an error message.
 	Rml::ElementDocument* invalid_document = context->LoadDocument("assets/invalid.rml");
-	RMLUI_ASSERTMSG(invalid_document != nullptr, "Testing ASSERT logging.");
-	if (invalid_document != nullptr)
+	RMLUI_ASSERTMSG(invalid_document, "Testing ASSERT logging.");
+	if (invalid_document)
 	{
 		invalid_document->Close();
 	}
@@ -121,12 +93,22 @@ int main(int RMLUI_UNUSED_PARAMETER(argc), char** RMLUI_UNUSED_PARAMETER(argv))
 		document->Show();
 	}
 
-	Shell::EventLoop(GameLoop);
+	bool running = true;
+	while (running)
+	{
+		running = Backend::ProcessEvents(context, &Shell::ProcessKeyDownShortcuts);
+
+		context->Update();
+
+		Backend::BeginFrame();
+		context->Render();
+		Backend::PresentFrame();
+	}
 
 	// Shutdown RmlUi.
 	Rml::Shutdown();
 
-	Shell::CloseWindow();
+	Backend::Shutdown();
 	Shell::Shutdown();
 
 	return 0;

+ 44 - 74
Samples/basic/databinding/src/main.cpp

@@ -28,12 +28,10 @@
 
 #include <RmlUi/Core.h>
 #include <RmlUi/Debugger.h>
-#include <Input.h>
+#include <RmlUi_Backend.h>
 #include <Shell.h>
-#include <ShellRenderInterfaceOpenGL.h>
 #include <numeric>
 
-
 namespace BasicExample {
 
 	Rml::DataModelHandle model_handle;
@@ -414,12 +412,10 @@ namespace FormsExample {
 }
 
 
-class DemoWindow : public Rml::EventListener
-{
+class DemoWindow : public Rml::EventListener {
 public:
-	DemoWindow(const Rml::String &title, Rml::Context *context)
+	DemoWindow(const Rml::String& title, Rml::Context* context)
 	{
-		using namespace Rml;
 		document = context->LoadDocument("basic/databinding/data/databinding.rml");
 		if (document)
 		{
@@ -428,7 +424,7 @@ public:
 		}
 	}
 
-	void Shutdown() 
+	void Shutdown()
 	{
 		if (document)
 		{
@@ -443,95 +439,53 @@ public:
 		{
 		case Rml::EventId::Keydown:
 		{
-			Rml::Input::KeyIdentifier key_identifier = (Rml::Input::KeyIdentifier) event.GetParameter< int >("key_identifier", 0);
+			Rml::Input::KeyIdentifier key_identifier = (Rml::Input::KeyIdentifier)event.GetParameter<int>("key_identifier", 0);
 
 			if (key_identifier == Rml::Input::KI_ESCAPE)
-			{
-				Shell::RequestExit();
-			}
+				Backend::RequestExit();
 		}
 		break;
-
 		default:
 			break;
 		}
 	}
 
-	Rml::ElementDocument * GetDocument() {
-		return document;
-	}
-
+	Rml::ElementDocument* GetDocument() { return document; }
 
 private:
-	Rml::ElementDocument *document = nullptr;
+	Rml::ElementDocument* document = nullptr;
 };
 
-
-
-Rml::Context* context = nullptr;
-ShellRenderInterfaceExtensions *shell_renderer;
-
-void GameLoop()
-{
-	static double t_prev = 0;
-	const double t = Rml::GetSystemInterface()->GetElapsedTime();
-	const double dt = Rml::Math::Min(t - t_prev, 0.1);
-	t_prev = t;
-
-	EventsExample::Update();
-	InvadersExample::Update(dt);
-
-	context->Update();
-
-	shell_renderer->PrepareRenderBuffer();
-	context->Render();
-	shell_renderer->PresentRenderBuffer();
-}
-
-
-
 #if defined RMLUI_PLATFORM_WIN32
-#include <windows.h>
-int APIENTRY WinMain(HINSTANCE RMLUI_UNUSED_PARAMETER(instance_handle), HINSTANCE RMLUI_UNUSED_PARAMETER(previous_instance_handle), char* RMLUI_UNUSED_PARAMETER(command_line), int RMLUI_UNUSED_PARAMETER(command_show))
+	#include <RmlUi_Include_Windows.h>
+int APIENTRY WinMain(HINSTANCE /*instance_handle*/, HINSTANCE /*previous_instance_handle*/, char* /*command_line*/, int /*command_show*/)
 #else
-int main(int RMLUI_UNUSED_PARAMETER(argc), char** RMLUI_UNUSED_PARAMETER(argv))
+int main(int /*argc*/, char** /*argv*/)
 #endif
 {
-#ifdef RMLUI_PLATFORM_WIN32
-	RMLUI_UNUSED(instance_handle);
-	RMLUI_UNUSED(previous_instance_handle);
-	RMLUI_UNUSED(command_line);
-	RMLUI_UNUSED(command_show);
-#else
-	RMLUI_UNUSED(argc);
-	RMLUI_UNUSED(argv);
-#endif
-
 	const int width = 1600;
 	const int height = 900;
 
-	ShellRenderInterfaceOpenGL opengl_renderer;
-	shell_renderer = &opengl_renderer;
+	// Initializes the shell which provides common functionality used by the included samples.
+	if (!Shell::Initialize())
+		return -1;
 
-	// Generic OS initialisation, creates a window and attaches OpenGL.
-	if (!Shell::Initialise() ||
-		!Shell::OpenWindow("Data Binding Sample", shell_renderer, width, height, true))
+	// Constructs the system and render interfaces, creates a window, and attaches the renderer.
+	if (!Backend::Initialize("Data Binding Sample", width, height, true))
 	{
 		Shell::Shutdown();
 		return -1;
 	}
 
-	// RmlUi initialisation.
-	Rml::SetRenderInterface(&opengl_renderer);
-	opengl_renderer.SetViewport(width, height);
-
-	ShellSystemInterface system_interface;
-	Rml::SetSystemInterface(&system_interface);
+	// Install the custom interfaces constructed by the backend before initializing RmlUi.
+	Rml::SetSystemInterface(Backend::GetSystemInterface());
+	Rml::SetRenderInterface(Backend::GetRenderInterface());
 
+	// RmlUi initialisation.
 	Rml::Initialise();
 
-	// Create the main RmlUi context and set it on the shell's input layer.
-	context = Rml::CreateContext("main", Rml::Vector2i(width, height));
+	// Create the main RmlUi context.
+	Rml::Context* context = Rml::CreateContext("main", Rml::Vector2i(width, height));
 
 	if (!context
 		|| !BasicExample::Initialize(context)
@@ -541,28 +495,44 @@ int main(int RMLUI_UNUSED_PARAMETER(argc), char** RMLUI_UNUSED_PARAMETER(argv))
 		)
 	{
 		Rml::Shutdown();
+		Backend::Shutdown();
 		Shell::Shutdown();
 		return -1;
 	}
 
 	Rml::Debugger::Initialise(context);
-	Input::SetContext(context);
-	Shell::SetContext(context);
-	
-	Shell::LoadFonts("assets/");
+	Shell::LoadFonts();
 
 	auto demo_window = Rml::MakeUnique<DemoWindow>("Data binding", context);
 	demo_window->GetDocument()->AddEventListener(Rml::EventId::Keydown, demo_window.get());
 	demo_window->GetDocument()->AddEventListener(Rml::EventId::Keyup, demo_window.get());
 
-	Shell::EventLoop(GameLoop);
+	double t_prev = 0;
+	bool running = true;
+	while (running)
+	{
+		running = Backend::ProcessEvents(context, &Shell::ProcessKeyDownShortcuts);
+
+		const double t = Rml::GetSystemInterface()->GetElapsedTime();
+		const double dt = Rml::Math::Min(t - t_prev, 0.1);
+		t_prev = t;
+
+		EventsExample::Update();
+		InvadersExample::Update(dt);
+
+		context->Update();
+
+		Backend::BeginFrame();
+		context->Render();
+		Backend::PresentFrame();
+	}
 
 	demo_window->Shutdown();
 
 	// Shutdown RmlUi.
 	Rml::Shutdown();
 
-	Shell::CloseWindow();
+	Backend::Shutdown();
 	Shell::Shutdown();
 
 	demo_window.reset();

+ 35 - 57
Samples/basic/demo/src/main.cpp

@@ -27,12 +27,11 @@
  */
 
 #include <RmlUi/Core.h>
+#include <RmlUi/Core/StreamMemory.h>
+#include <RmlUi/Core/TransformPrimitive.h>
 #include <RmlUi/Debugger.h>
-#include <Input.h>
+#include <RmlUi_Backend.h>
 #include <Shell.h>
-#include <ShellRenderInterfaceOpenGL.h>
-#include <RmlUi/Core/TransformPrimitive.h>
-#include <RmlUi/Core/StreamMemory.h>
 
 static const Rml::String sandbox_default_rcss = R"(
 body { top: 0; left: 0; right: 0; bottom: 0; overflow: hidden auto; }
@@ -50,7 +49,6 @@ scrollbarhorizontal sliderbar:hover { background: #888; }
 scrollbarhorizontal sliderbar:active { background: #666; }
 )";
 
-
 class DemoWindow : public Rml::EventListener
 {
 public:
@@ -190,9 +188,7 @@ public:
 			Rml::Input::KeyIdentifier key_identifier = (Rml::Input::KeyIdentifier) event.GetParameter< int >("key_identifier", 0);
 
 			if (key_identifier == Rml::Input::KI_ESCAPE)
-			{
-				Shell::RequestExit();
-			}
+				Backend::RequestExit();
 		}
 		break;
 
@@ -250,8 +246,6 @@ private:
 };
 
 
-Rml::Context* context = nullptr;
-ShellRenderInterfaceExtensions *shell_renderer;
 Rml::UniquePtr<DemoWindow> demo_window;
 
 struct TweeningParameters {
@@ -260,20 +254,6 @@ struct TweeningParameters {
 	float duration = 0.5f;
 } tweening_parameters;
 
-
-void GameLoop()
-{
-	demo_window->Update();
-	context->Update();
-
-	shell_renderer->PrepareRenderBuffer();
-	context->Render();
-	shell_renderer->PresentRenderBuffer();
-}
-
-
-
-
 class DemoEventListener : public Rml::EventListener
 {
 public:
@@ -295,7 +275,7 @@ public:
 		}
 		else if (value == "confirm_exit")
 		{
-			Shell::RequestExit();
+			Backend::RequestExit();
 		}
 		else if (value == "cancel_exit")
 		{
@@ -444,76 +424,74 @@ public:
 
 
 #if defined RMLUI_PLATFORM_WIN32
-#include <windows.h>
-int APIENTRY WinMain(HINSTANCE RMLUI_UNUSED_PARAMETER(instance_handle), HINSTANCE RMLUI_UNUSED_PARAMETER(previous_instance_handle), char* RMLUI_UNUSED_PARAMETER(command_line), int RMLUI_UNUSED_PARAMETER(command_show))
+	#include <RmlUi_Include_Windows.h>
+int APIENTRY WinMain(HINSTANCE /*instance_handle*/, HINSTANCE /*previous_instance_handle*/, char* /*command_line*/, int /*command_show*/)
 #else
-int main(int RMLUI_UNUSED_PARAMETER(argc), char** RMLUI_UNUSED_PARAMETER(argv))
+int main(int /*argc*/, char** /*argv*/)
 #endif
 {
-#ifdef RMLUI_PLATFORM_WIN32
-	RMLUI_UNUSED(instance_handle);
-	RMLUI_UNUSED(previous_instance_handle);
-	RMLUI_UNUSED(command_line);
-	RMLUI_UNUSED(command_show);
-#else
-	RMLUI_UNUSED(argc);
-	RMLUI_UNUSED(argv);
-#endif
-
 	const int width = 1600;
 	const int height = 890;
 
-	ShellRenderInterfaceOpenGL opengl_renderer;
-	shell_renderer = &opengl_renderer;
+	// Initializes the shell which provides common functionality used by the included samples.
+	if (!Shell::Initialize())
+		return -1;
 
-	// Generic OS initialisation, creates a window and attaches OpenGL.
-	if (!Shell::Initialise() ||
-		!Shell::OpenWindow("Demo Sample", shell_renderer, width, height, true))
+	// Constructs the system and render interfaces, creates a window, and attaches the renderer.
+	if (!Backend::Initialize("Demo Sample", width, height, true))
 	{
 		Shell::Shutdown();
 		return -1;
 	}
 
-	// RmlUi initialisation.
-	Rml::SetRenderInterface(&opengl_renderer);
-	opengl_renderer.SetViewport(width, height);
-
-	ShellSystemInterface system_interface;
-	Rml::SetSystemInterface(&system_interface);
+	// Install the custom interfaces constructed by the backend before initializing RmlUi.
+	Rml::SetSystemInterface(Backend::GetSystemInterface());
+	Rml::SetRenderInterface(Backend::GetRenderInterface());
 
+	// RmlUi initialisation.
 	Rml::Initialise();
 
-	// Create the main RmlUi context and set it on the shell's input layer.
-	context = Rml::CreateContext("main", Rml::Vector2i(width, height));
-	if (context == nullptr)
+	// Create the main RmlUi context.
+	Rml::Context* context = Rml::CreateContext("main", Rml::Vector2i(width, height));
+	if (!context)
 	{
 		Rml::Shutdown();
+		Backend::Shutdown();
 		Shell::Shutdown();
 		return -1;
 	}
 
 	Rml::Debugger::Initialise(context);
-	Input::SetContext(context);
-	Shell::SetContext(context);
 
 	DemoEventListenerInstancer event_listener_instancer;
 	Rml::Factory::RegisterEventListenerInstancer(&event_listener_instancer);
 
-	Shell::LoadFonts("assets/");
+	Shell::LoadFonts();
 
 	demo_window = Rml::MakeUnique<DemoWindow>("Demo sample", context);
 	demo_window->GetDocument()->AddEventListener(Rml::EventId::Keydown, demo_window.get());
 	demo_window->GetDocument()->AddEventListener(Rml::EventId::Keyup, demo_window.get());
 	demo_window->GetDocument()->AddEventListener(Rml::EventId::Animationend, demo_window.get());
 
-	Shell::EventLoop(GameLoop);
+	bool running = true;
+	while (running)
+	{
+		running = Backend::ProcessEvents(context, &Shell::ProcessKeyDownShortcuts);
+
+		demo_window->Update();
+		context->Update();
+
+		Backend::BeginFrame();
+		context->Render();
+		Backend::PresentFrame();
+	}
 
 	demo_window->Shutdown();
 
 	// Shutdown RmlUi.
 	Rml::Shutdown();
 
-	Shell::CloseWindow();
+	Backend::Shutdown();
 	Shell::Shutdown();
 
 	demo_window.reset();

+ 34 - 62
Samples/basic/drag/src/main.cpp

@@ -15,7 +15,7 @@
  *
  * The above copyright notice and this permission notice shall be included in
  * all copies or substantial portions of the Software.
- * 
+ *
  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
@@ -26,90 +26,52 @@
  *
  */
 
+#include "Inventory.h"
 #include <RmlUi/Core.h>
 #include <RmlUi/Debugger.h>
-#include <Input.h>
+#include <RmlUi_Backend.h>
 #include <Shell.h>
-#include <ShellRenderInterfaceOpenGL.h>
-#include "Inventory.h"
-
-Rml::Context* context = nullptr;
-
-ShellRenderInterfaceExtensions *shell_renderer;
-
-void GameLoop()
-{
-	context->Update();
-
-	shell_renderer->PrepareRenderBuffer();
-	context->Render();
-	shell_renderer->PresentRenderBuffer();
-}
 
 #if defined RMLUI_PLATFORM_WIN32
-#include <windows.h>
-int APIENTRY WinMain(HINSTANCE RMLUI_UNUSED_PARAMETER(instance_handle), HINSTANCE RMLUI_UNUSED_PARAMETER(previous_instance_handle), char* RMLUI_UNUSED_PARAMETER(command_line), int RMLUI_UNUSED_PARAMETER(command_show))
+	#include <RmlUi_Include_Windows.h>
+int APIENTRY WinMain(HINSTANCE /*instance_handle*/, HINSTANCE /*previous_instance_handle*/, char* /*command_line*/, int /*command_show*/)
 #else
-int main(int RMLUI_UNUSED_PARAMETER(argc), char** RMLUI_UNUSED_PARAMETER(argv))
+int main(int /*argc*/, char** /*argv*/)
 #endif
 {
-#ifdef RMLUI_PLATFORM_WIN32
-	RMLUI_UNUSED(instance_handle);
-	RMLUI_UNUSED(previous_instance_handle);
-	RMLUI_UNUSED(command_line);
-	RMLUI_UNUSED(command_show);
-#else
-	RMLUI_UNUSED(argc);
-	RMLUI_UNUSED(argv);
-#endif
-
-#ifdef RMLUI_PLATFORM_LINUX
-#define APP_PATH "../Samples/basic/drag/"
-#else
-#define APP_PATH "../../Samples/basic/drag/"
-#endif
-
-#ifdef RMLUI_PLATFORM_WIN32
-        AllocConsole();
-#endif
-
-    int window_width = 1024;
-    int window_height = 768;
+	int window_width = 1024;
+	int window_height = 768;
 
-	ShellRenderInterfaceOpenGL opengl_renderer;
-	shell_renderer = &opengl_renderer;
+	// Initializes the shell which provides common functionality used by the included samples.
+	if (!Shell::Initialize())
+		return -1;
 
-	// Generic OS initialisation, creates a window and attaches OpenGL.
-	if (!Shell::Initialise() ||
-		!Shell::OpenWindow("Drag Sample", shell_renderer, window_width, window_height, true))
+	// Constructs the system and render interfaces, creates a window, and attaches the renderer.
+	if (!Backend::Initialize("Drag Sample", window_width, window_height, true))
 	{
 		Shell::Shutdown();
 		return -1;
 	}
 
-	// RmlUi initialisation.
-	Rml::SetRenderInterface(&opengl_renderer);
-	opengl_renderer.SetViewport(window_width, window_height);
-
-	ShellSystemInterface system_interface;
-	Rml::SetSystemInterface(&system_interface);
+	// Install the custom interfaces constructed by the backend before initializing RmlUi.
+	Rml::SetSystemInterface(Backend::GetSystemInterface());
+	Rml::SetRenderInterface(Backend::GetRenderInterface());
 
+	// RmlUi initialisation.
 	Rml::Initialise();
 
-	// Create the main RmlUi context and set it on the shell's input layer.
-	context = Rml::CreateContext("main", Rml::Vector2i(window_width, window_height));
-	if (context == nullptr)
+	// Create the main RmlUi context.
+	Rml::Context* context = Rml::CreateContext("main", Rml::Vector2i(window_width, window_height));
+	if (!context)
 	{
 		Rml::Shutdown();
+		Backend::Shutdown();
 		Shell::Shutdown();
 		return -1;
 	}
 
 	Rml::Debugger::Initialise(context);
-	Input::SetContext(context);
-	Shell::SetContext(context);
-
-	Shell::LoadFonts("assets/");
+	Shell::LoadFonts();
 
 	// Load and show the inventory document.
 	Inventory* inventory_1 = new Inventory("Inventory 1", Rml::Vector2f(50, 200), context);
@@ -121,7 +83,17 @@ int main(int RMLUI_UNUSED_PARAMETER(argc), char** RMLUI_UNUSED_PARAMETER(argv))
 	inventory_1->AddItem("Closed-Loop Ion Beam");
 	inventory_1->AddItem("5kT Mega-Bomb");
 
-	Shell::EventLoop(GameLoop);
+	bool running = true;
+	while (running)
+	{
+		running = Backend::ProcessEvents(context, &Shell::ProcessKeyDownShortcuts);
+
+		context->Update();
+
+		Backend::BeginFrame();
+		context->Render();
+		Backend::PresentFrame();
+	}
 
 	delete inventory_1;
 	delete inventory_2;
@@ -129,7 +101,7 @@ int main(int RMLUI_UNUSED_PARAMETER(argc), char** RMLUI_UNUSED_PARAMETER(argv))
 	// Shutdown RmlUi.
 	Rml::Shutdown();
 
-	Shell::CloseWindow();
+	Backend::Shutdown();
 	Shell::Shutdown();
 
 	return 0;

+ 41 - 55
Samples/basic/loaddocument/src/main.cpp

@@ -15,7 +15,7 @@
  *
  * The above copyright notice and this permission notice shall be included in
  * all copies or substantial portions of the Software.
- * 
+ *
  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
@@ -28,92 +28,78 @@
 
 #include <RmlUi/Core.h>
 #include <RmlUi/Debugger.h>
-#include <Input.h>
+#include <RmlUi_Backend.h>
 #include <Shell.h>
-#include <ShellRenderInterfaceOpenGL.h>
-
-Rml::Context* context = nullptr;
-
-ShellRenderInterfaceExtensions *shell_renderer;
-
-void GameLoop()
-{
-	context->Update();
-
-	shell_renderer->PrepareRenderBuffer();
-	context->Render();
-	shell_renderer->PresentRenderBuffer();
-}
 
 #if defined RMLUI_PLATFORM_WIN32
-#include <windows.h>
-int APIENTRY WinMain(HINSTANCE RMLUI_UNUSED_PARAMETER(instance_handle), HINSTANCE RMLUI_UNUSED_PARAMETER(previous_instance_handle), char* RMLUI_UNUSED_PARAMETER(command_line), int RMLUI_UNUSED_PARAMETER(command_show))
+	#include <RmlUi_Include_Windows.h>
+int APIENTRY WinMain(HINSTANCE /*instance_handle*/, HINSTANCE /*previous_instance_handle*/, char* /*command_line*/, int /*command_show*/)
 #else
-int main(int RMLUI_UNUSED_PARAMETER(argc), char** RMLUI_UNUSED_PARAMETER(argv))
+int main(int /*argc*/, char** /*argv*/)
 #endif
 {
-#ifdef RMLUI_PLATFORM_WIN32
-	RMLUI_UNUSED(instance_handle);
-	RMLUI_UNUSED(previous_instance_handle);
-	RMLUI_UNUSED(command_line);
-	RMLUI_UNUSED(command_show);
-#else
-	RMLUI_UNUSED(argc);
-	RMLUI_UNUSED(argv);
-#endif
-
-#ifdef RMLUI_PLATFORM_WIN32
-        AllocConsole();
-#endif
+	const int window_width = 1024;
+	const int window_height = 768;
 
-    int window_width = 1024;
-    int window_height = 768;
-
-	ShellRenderInterfaceOpenGL opengl_renderer;
-	shell_renderer = &opengl_renderer;
+	// Initializes the shell which provides common functionality used by the included samples.
+	if (!Shell::Initialize())
+		return -1;
 
-	// Generic OS initialisation, creates a window and attaches OpenGL.
-	if (!Shell::Initialise() ||
-		!Shell::OpenWindow("Load Document Sample", shell_renderer, window_width, window_height, true))
+	// Constructs the system and render interfaces, creates a window, and attaches the renderer.
+	if (!Backend::Initialize("Load Document Sample", window_width, window_height, true))
 	{
 		Shell::Shutdown();
 		return -1;
 	}
 
-	// RmlUi initialisation.
-	Rml::SetRenderInterface(&opengl_renderer);
-	shell_renderer->SetViewport(window_width, window_height);
-
-	ShellSystemInterface system_interface;
-	Rml::SetSystemInterface(&system_interface);
+	// Install the custom interfaces constructed by the backend before initializing RmlUi.
+	Rml::SetSystemInterface(Backend::GetSystemInterface());
+	Rml::SetRenderInterface(Backend::GetRenderInterface());
 
+	// RmlUi initialisation.
 	Rml::Initialise();
 
-	// Create the main RmlUi context and set it on the shell's input layer.
-	context = Rml::CreateContext("main", Rml::Vector2i(window_width, window_height));
-	if (context == nullptr)
+	// Create the main RmlUi context.
+	Rml::Context* context = Rml::CreateContext("main", Rml::Vector2i(window_width, window_height));
+	if (!context)
 	{
 		Rml::Shutdown();
+		Backend::Shutdown();
 		Shell::Shutdown();
 		return -1;
 	}
 
+	// The RmlUi debugger is optional but very useful. Try it by pressing 'F8' after starting this sample.
 	Rml::Debugger::Initialise(context);
-	Input::SetContext(context);
-	Shell::SetContext(context);
 
-	Shell::LoadFonts("assets/");
+	// Fonts should be loaded before any documents are loaded.
+	Shell::LoadFonts();
 
 	// Load and show the demo document.
-	if (Rml::ElementDocument * document = context->LoadDocument("assets/demo.rml"))
+	if (Rml::ElementDocument* document = context->LoadDocument("assets/demo.rml"))
 		document->Show();
 
-	Shell::EventLoop(GameLoop);
+	bool running = true;
+	while (running)
+	{
+		// Handle input and window events.
+		running = Backend::ProcessEvents(context, &Shell::ProcessKeyDownShortcuts);
+
+		// This is a good place to update your game or application.
+
+		// Always update the context before rendering.
+		context->Update();
+
+		// Prepare the backend for taking rendering commands from RmlUi and then render the context.
+		Backend::BeginFrame();
+		context->Render();
+		Backend::PresentFrame();
+	}
 
 	// Shutdown RmlUi.
 	Rml::Shutdown();
 
-	Shell::CloseWindow();
+	Backend::Shutdown();
 	Shell::Shutdown();
 
 	return 0;

+ 30 - 48
Samples/basic/lottie/src/main.cpp

@@ -28,77 +28,49 @@
 
 #include <RmlUi/Core.h>
 #include <RmlUi/Debugger.h>
-#include <Input.h>
+#include <RmlUi_Backend.h>
 #include <Shell.h>
-#include <ShellRenderInterfaceOpenGL.h>
-
-Rml::Context* context = nullptr;
-
-ShellRenderInterfaceExtensions* shell_renderer;
-
-void GameLoop()
-{
-	context->Update();
-
-	shell_renderer->PrepareRenderBuffer();
-	context->Render();
-	shell_renderer->PresentRenderBuffer();
-}
 
 #if defined RMLUI_PLATFORM_WIN32
-#include <windows.h>
-int APIENTRY WinMain(HINSTANCE RMLUI_UNUSED_PARAMETER(instance_handle), HINSTANCE RMLUI_UNUSED_PARAMETER(previous_instance_handle), char* RMLUI_UNUSED_PARAMETER(command_line), int RMLUI_UNUSED_PARAMETER(command_show))
+	#include <RmlUi_Include_Windows.h>
+int APIENTRY WinMain(HINSTANCE /*instance_handle*/, HINSTANCE /*previous_instance_handle*/, char* /*command_line*/, int /*command_show*/)
 #else
-int main(int RMLUI_UNUSED_PARAMETER(argc), char** RMLUI_UNUSED_PARAMETER(argv))
+int main(int /*argc*/, char** /*argv*/)
 #endif
 {
-#ifdef RMLUI_PLATFORM_WIN32
-	RMLUI_UNUSED(instance_handle);
-	RMLUI_UNUSED(previous_instance_handle);
-	RMLUI_UNUSED(command_line);
-	RMLUI_UNUSED(command_show);
-#else
-	RMLUI_UNUSED(argc);
-	RMLUI_UNUSED(argv);
-#endif
-
 	int window_width = 1024;
 	int window_height = 768;
 
-	ShellRenderInterfaceOpenGL opengl_renderer;
-	shell_renderer = &opengl_renderer;
+	// Initializes the shell which provides common functionality used by the included samples.
+	if (!Shell::Initialize())
+		return -1;
 
-	// Generic OS initialisation, creates a window and attaches OpenGL.
-	if (!Shell::Initialise() ||
-		!Shell::OpenWindow("Lottie sample", shell_renderer, window_width, window_height, true))
+	// Constructs the system and render interfaces, creates a window, and attaches the renderer.
+	if (!Backend::Initialize("Lottie sample", window_width, window_height, true))
 	{
 		Shell::Shutdown();
 		return -1;
 	}
 
-	// RmlUi initialisation.
-	Rml::SetRenderInterface(&opengl_renderer);
-	shell_renderer->SetViewport(window_width, window_height);
-
-	ShellSystemInterface system_interface;
-	Rml::SetSystemInterface(&system_interface);
+	// Install the custom interfaces constructed by the backend before initializing RmlUi.
+	Rml::SetSystemInterface(Backend::GetSystemInterface());
+	Rml::SetRenderInterface(Backend::GetRenderInterface());
 
+	// RmlUi initialisation.
 	Rml::Initialise();
 
-	// Create the main RmlUi context and set it on the shell's input layer.
-	context = Rml::CreateContext("main", Rml::Vector2i(window_width, window_height));
-	if (context == nullptr)
+	// Create the main RmlUi context.
+	Rml::Context* context = Rml::CreateContext("main", Rml::Vector2i(window_width, window_height));
+	if (!context)
 	{
 		Rml::Shutdown();
+		Backend::Shutdown();
 		Shell::Shutdown();
 		return -1;
 	}
 
 	Rml::Debugger::Initialise(context);
-	Input::SetContext(context);
-	Shell::SetContext(context);
-
-	Shell::LoadFonts("assets/");
+	Shell::LoadFonts();
 
 	// Load and show the demo document.
 	if (Rml::ElementDocument* document = context->LoadDocument("basic/lottie/data/lottie.rml"))
@@ -107,12 +79,22 @@ int main(int RMLUI_UNUSED_PARAMETER(argc), char** RMLUI_UNUSED_PARAMETER(argv))
 		document->GetElementById("title")->SetInnerRML("Lottie");
 	}
 
-	Shell::EventLoop(GameLoop);
+	bool running = true;
+	while (running)
+	{
+		running = Backend::ProcessEvents(context, &Shell::ProcessKeyDownShortcuts);
+
+		context->Update();
+
+		Backend::BeginFrame();
+		context->Render();
+		Backend::PresentFrame();
+	}
 
 	// Shutdown RmlUi.
 	Rml::Shutdown();
 
-	Shell::CloseWindow();
+	Backend::Shutdown();
 	Shell::Shutdown();
 
 	return 0;

+ 0 - 194
Samples/basic/sdl2/src/RenderInterfaceSDL2.cpp

@@ -1,194 +0,0 @@
-/*
- * This source file is part of RmlUi, the HTML/CSS Interface Middleware
- *
- * For the latest information, see http://github.com/mikke89/RmlUi
- *
- * Copyright (c) 2008-2010 Nuno Silva
- * Copyright (c) 2019 The RmlUi Team, and contributors
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- * 
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- *
- */
-
-#include <RmlUi/Core.h>
-#include <SDL_image.h>
-
-#include "RenderInterfaceSDL2.h"
-
-#if !(SDL_VIDEO_RENDER_OGL)
-    #error "Only the opengl sdl backend is supported."
-#endif
-
-RmlUiSDL2Renderer::RmlUiSDL2Renderer(SDL_Renderer* renderer, SDL_Window* screen)
-{
-    mRenderer = renderer;
-    mScreen = screen;
-}
-
-// Called by RmlUi when it wants to render geometry that it does not wish to optimise.
-void RmlUiSDL2Renderer::RenderGeometry(Rml::Vertex* vertices, int num_vertices, int* indices, int num_indices, const Rml::TextureHandle texture, const Rml::Vector2f& translation)
-{
-    // SDL uses shaders that we need to disable here  
-    glUseProgramObjectARB(0);
-    glPushMatrix();
-    glTranslatef(translation.x, translation.y, 0);
- 
-    Rml::Vector<Rml::Vector2f> Positions(num_vertices);
-    Rml::Vector<Rml::Colourb> Colors(num_vertices);
-    Rml::Vector<Rml::Vector2f> TexCoords(num_vertices);
-    float texw = 0.0f;
-    float texh = 0.0f;
- 
-    SDL_Texture* sdl_texture = nullptr;
-    if(texture)
-    {
-        glEnableClientState(GL_TEXTURE_COORD_ARRAY);
-        sdl_texture = (SDL_Texture *) texture;
-        SDL_GL_BindTexture(sdl_texture, &texw, &texh);
-    }
- 
-    for(int  i = 0; i < num_vertices; i++) {
-        Positions[i] = vertices[i].position;
-        Colors[i] = vertices[i].colour;
-        if (sdl_texture) {
-            TexCoords[i].x = vertices[i].tex_coord.x * texw;
-            TexCoords[i].y = vertices[i].tex_coord.y * texh;
-        }
-        else TexCoords[i] = vertices[i].tex_coord;
-    };
- 
-    glEnableClientState(GL_VERTEX_ARRAY);
-    glEnableClientState(GL_COLOR_ARRAY);
-    glVertexPointer(2, GL_FLOAT, 0, &Positions[0]);
-    glColorPointer(4, GL_UNSIGNED_BYTE, 0, &Colors[0]);
-    glTexCoordPointer(2, GL_FLOAT, 0, &TexCoords[0]);
- 
-    glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
-    glEnable(GL_BLEND);
-    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
-    glDrawElements(GL_TRIANGLES, num_indices, GL_UNSIGNED_INT, indices);
-    glDisableClientState(GL_VERTEX_ARRAY);
-    glDisableClientState(GL_COLOR_ARRAY);
- 
-    if (sdl_texture) {
-        SDL_GL_UnbindTexture(sdl_texture);
-        glDisableClientState(GL_TEXTURE_COORD_ARRAY);
-    }
- 
-    glColor4f(1.0, 1.0, 1.0, 1.0);
-    glPopMatrix();
-    /* Reset blending and draw a fake point just outside the screen to let SDL know that it needs to reset its state in case it wants to render a texture */
-    glDisable(GL_BLEND);
-    SDL_SetRenderDrawBlendMode(mRenderer, SDL_BLENDMODE_NONE);
-    SDL_RenderDrawPoint(mRenderer, -1, -1);
-}
-
-
-// Called by RmlUi when it wants to enable or disable scissoring to clip content.		
-void RmlUiSDL2Renderer::EnableScissorRegion(bool enable)
-{
-    if (enable)
-        glEnable(GL_SCISSOR_TEST);
-    else
-        glDisable(GL_SCISSOR_TEST);
-}
-
-// Called by RmlUi when it wants to change the scissor region.		
-void RmlUiSDL2Renderer::SetScissorRegion(int x, int y, int width, int height)
-{
-    int w_width, w_height;
-    SDL_GetWindowSize(mScreen, &w_width, &w_height);
-    glScissor(x, w_height - (y + height), width, height);
-}
-
-// Called by RmlUi when a texture is required by the library.		
-bool RmlUiSDL2Renderer::LoadTexture(Rml::TextureHandle& texture_handle, Rml::Vector2i& texture_dimensions, const Rml::String& source)
-{
-
-    Rml::FileInterface* file_interface = Rml::GetFileInterface();
-    Rml::FileHandle file_handle = file_interface->Open(source);
-    if (!file_handle)
-        return false;
-
-    file_interface->Seek(file_handle, 0, SEEK_END);
-    size_t buffer_size = file_interface->Tell(file_handle);
-    file_interface->Seek(file_handle, 0, SEEK_SET);
-
-    char* buffer = new char[buffer_size];
-    file_interface->Read(buffer, buffer_size, file_handle);
-    file_interface->Close(file_handle);
-
-    size_t i;
-    for(i = source.length() - 1; i > 0; i--)
-    {
-        if(source[i] == '.')
-            break;
-    }
-
-    Rml::String extension = source.substr(i+1, source.length()-i);
-
-    SDL_Surface* surface = IMG_LoadTyped_RW(SDL_RWFromMem(buffer, int(buffer_size)), 1, extension.c_str());
-
-    if (surface) {
-        SDL_Texture *texture = SDL_CreateTextureFromSurface(mRenderer, surface);
-
-        if (texture) {
-            texture_handle = (Rml::TextureHandle) texture;
-            texture_dimensions = Rml::Vector2i(surface->w, surface->h);
-            SDL_FreeSurface(surface);
-        }
-        else
-        {
-            return false;
-        }
-
-        return true;
-    }
-
-    return false;
-}
-
-// Called by RmlUi when a texture is required to be built from an internally-generated sequence of pixels.
-bool RmlUiSDL2Renderer::GenerateTexture(Rml::TextureHandle& texture_handle, const Rml::byte* source, const Rml::Vector2i& source_dimensions)
-{
-    #if SDL_BYTEORDER == SDL_BIG_ENDIAN
-        Uint32 rmask = 0xff000000;
-        Uint32 gmask = 0x00ff0000;
-        Uint32 bmask = 0x0000ff00;
-        Uint32 amask = 0x000000ff;
-    #else
-        Uint32 rmask = 0x000000ff;
-        Uint32 gmask = 0x0000ff00;
-        Uint32 bmask = 0x00ff0000;
-        Uint32 amask = 0xff000000;
-    #endif
-
-    SDL_Surface *surface = SDL_CreateRGBSurfaceFrom ((void*) source, source_dimensions.x, source_dimensions.y, 32, source_dimensions.x*4, rmask, gmask, bmask, amask);
-    SDL_Texture *texture = SDL_CreateTextureFromSurface(mRenderer, surface);
-    SDL_SetTextureBlendMode(texture, SDL_BLENDMODE_BLEND);
-    SDL_FreeSurface(surface);
-    texture_handle = (Rml::TextureHandle) texture;
-    return true;
-}
-
-// Called by RmlUi when a loaded texture is no longer required.		
-void RmlUiSDL2Renderer::ReleaseTexture(Rml::TextureHandle texture_handle)
-{
-    SDL_DestroyTexture((SDL_Texture*) texture_handle);
-}

+ 0 - 442
Samples/basic/sdl2/src/SystemInterfaceSDL2.cpp

@@ -1,442 +0,0 @@
-/*
- * This source file is part of RmlUi, the HTML/CSS Interface Middleware
- *
- * For the latest information, see http://github.com/mikke89/RmlUi
- *
- * Copyright (c) 2008-2010 Nuno Silva
- * Copyright (c) 2019 The RmlUi Team, and contributors
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- * 
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- *
- */
-#include <RmlUi/Core.h>
-#include "SystemInterfaceSDL2.h"
-
-Rml::Input::KeyIdentifier RmlUiSDL2SystemInterface::TranslateKey(SDL_Keycode sdlkey)
-{
-    using namespace Rml::Input;
-
-
-    switch(sdlkey) {
-        case SDLK_UNKNOWN:
-            return KI_UNKNOWN;
-            break;
-        case SDLK_SPACE:
-            return KI_SPACE;
-            break;
-        case SDLK_0:
-            return KI_0;
-            break;
-        case SDLK_1:
-            return KI_1;
-            break;
-        case SDLK_2:
-            return KI_2;
-            break;
-        case SDLK_3:
-            return KI_3;
-            break;
-        case SDLK_4:
-            return KI_4;
-            break;
-        case SDLK_5:
-            return KI_5;
-            break;
-        case SDLK_6:
-            return KI_6;
-            break;
-        case SDLK_7:
-            return KI_7;
-            break;
-        case SDLK_8:
-            return KI_8;
-            break;
-        case SDLK_9:
-            return KI_9;
-            break;
-        case SDLK_a:
-            return KI_A;
-            break;
-        case SDLK_b:
-            return KI_B;
-            break;
-        case SDLK_c:
-            return KI_C;
-            break;
-        case SDLK_d:
-            return KI_D;
-            break;
-        case SDLK_e:
-            return KI_E;
-            break;
-        case SDLK_f:
-            return KI_F;
-            break;
-        case SDLK_g:
-            return KI_G;
-            break;
-        case SDLK_h:
-            return KI_H;
-            break;
-        case SDLK_i:
-            return KI_I;
-            break;
-        case SDLK_j:
-            return KI_J;
-            break;
-        case SDLK_k:
-            return KI_K;
-            break;
-        case SDLK_l:
-            return KI_L;
-            break;
-        case SDLK_m:
-            return KI_M;
-            break;
-        case SDLK_n:
-            return KI_N;
-            break;
-        case SDLK_o:
-            return KI_O;
-            break;
-        case SDLK_p:
-            return KI_P;
-            break;
-        case SDLK_q:
-            return KI_Q;
-            break;
-        case SDLK_r:
-            return KI_R;
-            break;
-        case SDLK_s:
-            return KI_S;
-            break;
-        case SDLK_t:
-            return KI_T;
-            break;
-        case SDLK_u:
-            return KI_U;
-            break;
-        case SDLK_v:
-            return KI_V;
-            break;
-        case SDLK_w:
-            return KI_W;
-            break;
-        case SDLK_x:
-            return KI_X;
-            break;
-        case SDLK_y:
-            return KI_Y;
-            break;
-        case SDLK_z:
-            return KI_Z;
-            break;
-        case SDLK_SEMICOLON:
-            return KI_OEM_1;
-            break;
-        case SDLK_PLUS:
-            return KI_OEM_PLUS;
-            break;
-        case SDLK_COMMA:
-            return KI_OEM_COMMA;
-            break;
-        case SDLK_MINUS:
-            return KI_OEM_MINUS;
-            break;
-        case SDLK_PERIOD:
-            return KI_OEM_PERIOD;
-            break;
-        case SDLK_SLASH:
-            return KI_OEM_2;
-            break;
-        case SDLK_BACKQUOTE:
-            return KI_OEM_3;
-            break;
-        case SDLK_LEFTBRACKET:
-            return KI_OEM_4;
-            break;
-        case SDLK_BACKSLASH:
-            return KI_OEM_5;
-            break;
-        case SDLK_RIGHTBRACKET:
-            return KI_OEM_6;
-            break;
-        case SDLK_QUOTEDBL:
-            return KI_OEM_7;
-            break;
-        case SDLK_KP_0:
-            return KI_NUMPAD0;
-            break;
-        case SDLK_KP_1:
-            return KI_NUMPAD1;
-            break;
-        case SDLK_KP_2:
-            return KI_NUMPAD2;
-            break;
-        case SDLK_KP_3:
-            return KI_NUMPAD3;
-            break;
-        case SDLK_KP_4:
-            return KI_NUMPAD4;
-            break;
-        case SDLK_KP_5:
-            return KI_NUMPAD5;
-            break;
-        case SDLK_KP_6:
-            return KI_NUMPAD6;
-            break;
-        case SDLK_KP_7:
-            return KI_NUMPAD7;
-            break;
-        case SDLK_KP_8:
-            return KI_NUMPAD8;
-            break;
-        case SDLK_KP_9:
-            return KI_NUMPAD9;
-            break;
-        case SDLK_KP_ENTER:
-            return KI_NUMPADENTER;
-            break;
-        case SDLK_KP_MULTIPLY:
-            return KI_MULTIPLY;
-            break;
-        case SDLK_KP_PLUS:
-            return KI_ADD;
-            break;
-        case SDLK_KP_MINUS:
-            return KI_SUBTRACT;
-            break;
-        case SDLK_KP_PERIOD:
-            return KI_DECIMAL;
-            break;
-        case SDLK_KP_DIVIDE:
-            return KI_DIVIDE;
-            break;
-        case SDLK_KP_EQUALS:
-            return KI_OEM_NEC_EQUAL;
-            break;
-        case SDLK_BACKSPACE:
-            return KI_BACK;
-            break;
-        case SDLK_TAB:
-            return KI_TAB;
-            break;
-        case SDLK_CLEAR:
-            return KI_CLEAR;
-            break;
-        case SDLK_RETURN:
-            return KI_RETURN;
-            break;
-        case SDLK_PAUSE:
-            return KI_PAUSE;
-            break;
-        case SDLK_CAPSLOCK:
-            return KI_CAPITAL;
-            break;
-        case SDLK_PAGEUP:
-            return KI_PRIOR;
-            break;
-        case SDLK_PAGEDOWN:
-            return KI_NEXT;
-            break;
-        case SDLK_END:
-            return KI_END;
-            break;
-        case SDLK_HOME:
-            return KI_HOME;
-            break;
-        case SDLK_LEFT:
-            return KI_LEFT;
-            break;
-        case SDLK_UP:
-            return KI_UP;
-            break;
-        case SDLK_RIGHT:
-            return KI_RIGHT;
-            break;
-        case SDLK_DOWN:
-            return KI_DOWN;
-            break;
-        case SDLK_INSERT:
-            return KI_INSERT;
-            break;
-        case SDLK_DELETE:
-            return KI_DELETE;
-            break;
-        case SDLK_HELP:
-            return KI_HELP;
-            break;
-        case SDLK_F1:
-            return KI_F1;
-            break;
-        case SDLK_F2:
-            return KI_F2;
-            break;
-        case SDLK_F3:
-            return KI_F3;
-            break;
-        case SDLK_F4:
-            return KI_F4;
-            break;
-        case SDLK_F5:
-            return KI_F5;
-            break;
-        case SDLK_F6:
-            return KI_F6;
-            break;
-        case SDLK_F7:
-            return KI_F7;
-            break;
-        case SDLK_F8:
-            return KI_F8;
-            break;
-        case SDLK_F9:
-            return KI_F9;
-            break;
-        case SDLK_F10:
-            return KI_F10;
-            break;
-        case SDLK_F11:
-            return KI_F11;
-            break;
-        case SDLK_F12:
-            return KI_F12;
-            break;
-        case SDLK_F13:
-            return KI_F13;
-            break;
-        case SDLK_F14:
-            return KI_F14;
-            break;
-        case SDLK_F15:
-            return KI_F15;
-            break;
-        case SDLK_NUMLOCKCLEAR:
-            return KI_NUMLOCK;
-            break;
-        case SDLK_SCROLLLOCK:
-            return KI_SCROLL;
-            break;
-        case SDLK_LSHIFT:
-            return KI_LSHIFT;
-            break;
-        case SDLK_RSHIFT:
-            return KI_RSHIFT;
-            break;
-        case SDLK_LCTRL:
-            return KI_LCONTROL;
-            break;
-        case SDLK_RCTRL:
-            return KI_RCONTROL;
-            break;
-        case SDLK_LALT:
-            return KI_LMENU;
-            break;
-        case SDLK_RALT:
-            return KI_RMENU;
-            break;
-        case SDLK_LGUI:
-            return KI_LMETA;
-            break;
-        case SDLK_RGUI:
-            return KI_RMETA;
-            break;
-        /*case SDLK_LSUPER:
-            return KI_LWIN;
-            break;
-        case SDLK_RSUPER:
-            return KI_RWIN;
-            break;*/
-        default:
-            return KI_UNKNOWN;
-            break;
-    }
-}
-
-int RmlUiSDL2SystemInterface::TranslateMouseButton(Uint8 button)
-{
-    switch(button)
-    {
-        case SDL_BUTTON_LEFT:
-            return 0;
-        case SDL_BUTTON_RIGHT:
-            return 1;
-        case SDL_BUTTON_MIDDLE:
-            return 2;
-        default:
-            return 3;
-    }
-}
-
-int RmlUiSDL2SystemInterface::GetKeyModifiers()
-{
-    SDL_Keymod sdlMods = SDL_GetModState();
-
-    int retval = 0;
-
-    if(sdlMods & KMOD_CTRL)
-        retval |= Rml::Input::KM_CTRL;
-
-    if(sdlMods & KMOD_SHIFT)
-        retval |= Rml::Input::KM_SHIFT;
-
-    if(sdlMods & KMOD_ALT)
-        retval |= Rml::Input::KM_ALT;
-
-    return retval;
-}
-
-double RmlUiSDL2SystemInterface::GetElapsedTime()
-{
-	return double(SDL_GetTicks()) / 1000.0;
-}
-
-bool RmlUiSDL2SystemInterface::LogMessage(Rml::Log::Type type, const Rml::String& message)
-{
-	Rml::String Type;
-
-	switch(type)
-	{
-	case Rml::Log::LT_ALWAYS:
-		Type = "[Always]";
-		break;
-	case Rml::Log::LT_ERROR:
-		Type = "[Error]";
-		break;
-	case Rml::Log::LT_ASSERT:
-		Type = "[Assert]";
-		break;
-	case Rml::Log::LT_WARNING:
-		Type = "[Warning]";
-		break;
-	case Rml::Log::LT_INFO:
-		Type = "[Info]";
-		break;
-	case Rml::Log::LT_DEBUG:
-		Type = "[Debug]";
-		break;
-    case Rml::Log::LT_MAX:
-        break;
-	};
-
-	printf("%s - %s\n", Type.c_str(), message.c_str());
-
-	return true;
-}

+ 0 - 46
Samples/basic/sdl2/src/SystemInterfaceSDL2.h

@@ -1,46 +0,0 @@
-/*
- * This source file is part of RmlUi, the HTML/CSS Interface Middleware
- *
- * For the latest information, see http://github.com/mikke89/RmlUi
- *
- * Copyright (c) 2008-2010 Nuno Silva
- * Copyright (c) 2019 The RmlUi Team, and contributors
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- * 
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- *
- */
-#ifndef SYSTEMINTEFACESDL2_H
-#define SYSTEMINTEFACESDL2_H
-
-#include <RmlUi/Core/SystemInterface.h>
-#include <RmlUi/Core/Input.h>
-
-#include <SDL.h>
-
-class RmlUiSDL2SystemInterface : public Rml::SystemInterface
-{
-public:
-    Rml::Input::KeyIdentifier TranslateKey(SDL_Keycode sdlkey);
-    int TranslateMouseButton(Uint8 button);
-	int GetKeyModifiers();
-	
-	double GetElapsedTime() override;
-    bool LogMessage(Rml::Log::Type type, const Rml::String& message) override;
-};
-#endif

+ 0 - 194
Samples/basic/sdl2/src/main.cpp

@@ -1,194 +0,0 @@
-/*
- * This source file is part of RmlUi, the HTML/CSS Interface Middleware
- *
- * For the latest information, see http://github.com/mikke89/RmlUi
- *
- * Copyright (c) 2008-2010 Nuno Silva
- * Copyright (c) 2019 The RmlUi Team, and contributors
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- * 
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- *
- */
-
-#include <RmlUi/Core.h>
-#include <RmlUi/Core/Input.h>
-#include <RmlUi/Debugger/Debugger.h>
-#include <Shell.h>
-#include <ShellFileInterface.h>
-#include <string.h>
-
-#include "SystemInterfaceSDL2.h"
-#include "RenderInterfaceSDL2.h"
-
-#ifdef RMLUI_PLATFORM_WIN32
-#include <windows.h>
-#endif
-
-#include <SDL.h>
-
-#include <GL/glew.h>
-
-int main(int /*argc*/, char** /*argv*/)
-{
-#ifdef RMLUI_PLATFORM_WIN32
-	AllocConsole();
-#endif
-
-	int window_width = 1024;
-	int window_height = 768;
-
-	SDL_Init(SDL_INIT_VIDEO);
-	SDL_Window* screen = SDL_CreateWindow("LibRmlUi SDL2 test", 20, 20, window_width, window_height, SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE);
-	SDL_GLContext glcontext = SDL_GL_CreateContext(screen);
-	int oglIdx = -1;
-	int nRD = SDL_GetNumRenderDrivers();
-	for (int i = 0; i < nRD; i++)
-	{
-		SDL_RendererInfo info;
-		if (!SDL_GetRenderDriverInfo(i, &info))
-		{
-			if (!strcmp(info.name, "opengl"))
-			{
-				oglIdx = i;
-			}
-		}
-	}
-	SDL_Renderer* renderer = SDL_CreateRenderer(screen, oglIdx, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC);
-
-	GLenum err = glewInit();
-
-	if (err != GLEW_OK)
-		fprintf(stderr, "GLEW ERROR: %s\n", glewGetErrorString(err));
-
-	SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
-	glMatrixMode(GL_PROJECTION | GL_MODELVIEW);
-	glLoadIdentity();
-	glOrtho(0, window_width, window_height, 0, 0, 1);
-
-	RmlUiSDL2Renderer Renderer(renderer, screen);
-	RmlUiSDL2SystemInterface SystemInterface;
-
-	Rml::String root = Shell::FindSamplesRoot();
-	ShellFileInterface FileInterface(root);
-
-	Rml::SetFileInterface(&FileInterface);
-	Rml::SetRenderInterface(&Renderer);
-	Rml::SetSystemInterface(&SystemInterface);
-
-	if (!Rml::Initialise())
-		return 1;
-
-	struct FontFace {
-		Rml::String filename;
-		bool fallback_face;
-	};
-	FontFace font_faces[] = {
-		{ "LatoLatin-Regular.ttf",    false },
-		{ "LatoLatin-Italic.ttf",     false },
-		{ "LatoLatin-Bold.ttf",       false },
-		{ "LatoLatin-BoldItalic.ttf", false },
-		{ "NotoEmoji-Regular.ttf",    true  },
-	};
-
-	for (const FontFace& face : font_faces)
-	{
-		Rml::LoadFontFace("assets/" + face.filename, face.fallback_face);
-	}
-
-	Rml::Context* Context = Rml::CreateContext("default",
-		Rml::Vector2i(window_width, window_height));
-
-	Rml::Debugger::Initialise(Context);
-
-	Rml::ElementDocument* Document = Context->LoadDocument("assets/demo.rml");
-
-	if (Document)
-	{
-		Document->Show();
-		fprintf(stdout, "\nDocument loaded");
-	}
-	else
-	{
-		fprintf(stdout, "\nDocument is nullptr");
-	}
-
-	bool done = false;
-
-	while (!done)
-	{
-		SDL_Event event;
-
-		SDL_SetRenderDrawColor(renderer, 0, 0, 255, 255);
-		SDL_RenderClear(renderer);
-
-		Context->Render();
-		SDL_RenderPresent(renderer);
-
-		while (SDL_PollEvent(&event))
-		{
-			switch (event.type)
-			{
-			case SDL_QUIT:
-				done = true;
-				break;
-
-			case SDL_MOUSEMOTION:
-				Context->ProcessMouseMove(event.motion.x, event.motion.y, SystemInterface.GetKeyModifiers());
-				break;
-			case SDL_MOUSEBUTTONDOWN:
-				Context->ProcessMouseButtonDown(SystemInterface.TranslateMouseButton(event.button.button), SystemInterface.GetKeyModifiers());
-				break;
-
-			case SDL_MOUSEBUTTONUP:
-				Context->ProcessMouseButtonUp(SystemInterface.TranslateMouseButton(event.button.button), SystemInterface.GetKeyModifiers());
-				break;
-
-			case SDL_MOUSEWHEEL:
-				Context->ProcessMouseWheel(float(event.wheel.y), SystemInterface.GetKeyModifiers());
-				break;
-
-			case SDL_KEYDOWN:
-			{
-				// Intercept F8 key stroke to toggle RmlUi's visual debugger tool
-				if (event.key.keysym.sym == SDLK_F8)
-				{
-					Rml::Debugger::SetVisible(!Rml::Debugger::IsVisible());
-					break;
-				}
-
-				Context->ProcessKeyDown(SystemInterface.TranslateKey(event.key.keysym.sym), SystemInterface.GetKeyModifiers());
-				break;
-			}
-
-			default:
-				break;
-			}
-		}
-		Context->Update();
-	}
-
-	Rml::Shutdown();
-
-	SDL_DestroyRenderer(renderer);
-	SDL_GL_DeleteContext(glcontext);
-	SDL_DestroyWindow(screen);
-	SDL_Quit();
-
-	return 0;
-}

+ 0 - 171
Samples/basic/sdl2_sdlrenderer/src/RenderInterfaceSDL2.cpp

@@ -1,171 +0,0 @@
-/*
- * This source file is part of RmlUi, the HTML/CSS Interface Middleware
- *
- * For the latest information, see http://github.com/mikke89/RmlUi
- *
- * Copyright (c) 2008-2010 Nuno Silva
- * Copyright (c) 2019 The RmlUi Team, and contributors
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- * 
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- *
- */
-
-#include <RmlUi/Core.h>
-#include <SDL_image.h>
-
-#include "RenderInterfaceSDL2.h"
-
-RmlUiSDL2Renderer::RmlUiSDL2Renderer(SDL_Renderer* renderer, SDL_Window* screen)
-{
-    mRenderer = renderer;
-    mScreen = screen;
-
-    SDL_GetRendererOutputSize(renderer, &mRenderer_w, &mRenderer_h);
-
-    mRectScisor.x = 0;
-    mRectScisor.y = 0;
-    mRectScisor.w = mRenderer_w;
-    mRectScisor.h = mRenderer_h;
-}
-
-// Called by RmlUi when it wants to render geometry that it does not wish to optimise.
-void RmlUiSDL2Renderer::RenderGeometry(Rml::Vertex* vertices, int num_vertices, int* indices, int num_indices, const Rml::TextureHandle texture, const Rml::Vector2f& translation)
-{
-    SDL_Texture *sdl_texture = (SDL_Texture *) texture;
-
-    SDL_Rect r;
-    r.x = (int)translation.x;
-    r.y = (int)translation.y;
-    r.w = mRenderer_w - r.x;
-    r.h = mRenderer_h - r.y;
-    
-    SDL_RenderSetViewport(mRenderer, &r);
-
-    if (sdl_texture) {
-        SDL_SetTextureBlendMode(sdl_texture, SDL_BLENDMODE_BLEND);
-    }
-
-    int sz = sizeof(vertices[0]);
-    int off1 = offsetof(Rml::Vertex, position);
-    int off2 = offsetof(Rml::Vertex, colour);
-    int off3 = offsetof(Rml::Vertex, tex_coord);
-    SDL_RenderGeometryRaw(mRenderer, sdl_texture, 
-            (float *)((Uint8 *) vertices + off1), sz,
-            (SDL_Color *)((Uint8 *) vertices + off2), sz,
-            (float *)((Uint8 *) vertices + off3), sz,
-            num_vertices, indices, num_indices, 4);
-
-}
-
-// Called by RmlUi when it wants to enable or disable scissoring to clip content.		
-void RmlUiSDL2Renderer::EnableScissorRegion(bool enable)
-{
-    if (enable) {
-        SDL_RenderSetClipRect(mRenderer, &mRectScisor);
-    } else {
-        SDL_RenderSetClipRect(mRenderer, NULL);
-    }
-}
-
-// Called by RmlUi when it wants to change the scissor region.		
-void RmlUiSDL2Renderer::SetScissorRegion(int x, int y, int width, int height)
-{
-    int w_width, w_height;
-    SDL_GetWindowSize(mScreen, &w_width, &w_height);
-    mRectScisor.x = x;
-    mRectScisor.y = w_height - (y + height);
-    mRectScisor.w = width;
-    mRectScisor.h = height;
-}
-
-// Called by RmlUi when a texture is required by the library.		
-bool RmlUiSDL2Renderer::LoadTexture(Rml::TextureHandle& texture_handle, Rml::Vector2i& texture_dimensions, const Rml::String& source)
-{
-
-    Rml::FileInterface* file_interface = Rml::GetFileInterface();
-    Rml::FileHandle file_handle = file_interface->Open(source);
-    if (!file_handle)
-        return false;
-
-    file_interface->Seek(file_handle, 0, SEEK_END);
-    size_t buffer_size = file_interface->Tell(file_handle);
-    file_interface->Seek(file_handle, 0, SEEK_SET);
-
-    char* buffer = new char[buffer_size];
-    file_interface->Read(buffer, buffer_size, file_handle);
-    file_interface->Close(file_handle);
-
-    size_t i;
-    for(i = source.length() - 1; i > 0; i--)
-    {
-        if(source[i] == '.')
-            break;
-    }
-
-    Rml::String extension = source.substr(i+1, source.length()-i);
-
-    SDL_Surface* surface = IMG_LoadTyped_RW(SDL_RWFromMem(buffer, int(buffer_size)), 1, extension.c_str());
-
-    if (surface) {
-        SDL_Texture *texture = SDL_CreateTextureFromSurface(mRenderer, surface);
-
-        if (texture) {
-            texture_handle = (Rml::TextureHandle) texture;
-            texture_dimensions = Rml::Vector2i(surface->w, surface->h);
-            SDL_FreeSurface(surface);
-        }
-        else
-        {
-            return false;
-        }
-
-        return true;
-    }
-
-    return false;
-}
-
-// Called by RmlUi when a texture is required to be built from an internally-generated sequence of pixels.
-bool RmlUiSDL2Renderer::GenerateTexture(Rml::TextureHandle& texture_handle, const Rml::byte* source, const Rml::Vector2i& source_dimensions)
-{
-    #if SDL_BYTEORDER == SDL_BIG_ENDIAN
-        Uint32 rmask = 0xff000000;
-        Uint32 gmask = 0x00ff0000;
-        Uint32 bmask = 0x0000ff00;
-        Uint32 amask = 0x000000ff;
-    #else
-        Uint32 rmask = 0x000000ff;
-        Uint32 gmask = 0x0000ff00;
-        Uint32 bmask = 0x00ff0000;
-        Uint32 amask = 0xff000000;
-    #endif
-
-    SDL_Surface *surface = SDL_CreateRGBSurfaceFrom ((void*) source, source_dimensions.x, source_dimensions.y, 32, source_dimensions.x*4, rmask, gmask, bmask, amask);
-    SDL_Texture *texture = SDL_CreateTextureFromSurface(mRenderer, surface);
-    SDL_SetTextureBlendMode(texture, SDL_BLENDMODE_BLEND);
-    SDL_FreeSurface(surface);
-    texture_handle = (Rml::TextureHandle) texture;
-    return true;
-}
-
-// Called by RmlUi when a loaded texture is no longer required.		
-void RmlUiSDL2Renderer::ReleaseTexture(Rml::TextureHandle texture_handle)
-{
-    SDL_DestroyTexture((SDL_Texture*) texture_handle);
-}

+ 0 - 442
Samples/basic/sdl2_sdlrenderer/src/SystemInterfaceSDL2.cpp

@@ -1,442 +0,0 @@
-/*
- * This source file is part of RmlUi, the HTML/CSS Interface Middleware
- *
- * For the latest information, see http://github.com/mikke89/RmlUi
- *
- * Copyright (c) 2008-2010 Nuno Silva
- * Copyright (c) 2019 The RmlUi Team, and contributors
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- * 
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- *
- */
-#include <RmlUi/Core.h>
-#include "SystemInterfaceSDL2.h"
-
-Rml::Input::KeyIdentifier RmlUiSDL2SystemInterface::TranslateKey(SDL_Keycode sdlkey)
-{
-    using namespace Rml::Input;
-
-
-    switch(sdlkey) {
-        case SDLK_UNKNOWN:
-            return KI_UNKNOWN;
-            break;
-        case SDLK_SPACE:
-            return KI_SPACE;
-            break;
-        case SDLK_0:
-            return KI_0;
-            break;
-        case SDLK_1:
-            return KI_1;
-            break;
-        case SDLK_2:
-            return KI_2;
-            break;
-        case SDLK_3:
-            return KI_3;
-            break;
-        case SDLK_4:
-            return KI_4;
-            break;
-        case SDLK_5:
-            return KI_5;
-            break;
-        case SDLK_6:
-            return KI_6;
-            break;
-        case SDLK_7:
-            return KI_7;
-            break;
-        case SDLK_8:
-            return KI_8;
-            break;
-        case SDLK_9:
-            return KI_9;
-            break;
-        case SDLK_a:
-            return KI_A;
-            break;
-        case SDLK_b:
-            return KI_B;
-            break;
-        case SDLK_c:
-            return KI_C;
-            break;
-        case SDLK_d:
-            return KI_D;
-            break;
-        case SDLK_e:
-            return KI_E;
-            break;
-        case SDLK_f:
-            return KI_F;
-            break;
-        case SDLK_g:
-            return KI_G;
-            break;
-        case SDLK_h:
-            return KI_H;
-            break;
-        case SDLK_i:
-            return KI_I;
-            break;
-        case SDLK_j:
-            return KI_J;
-            break;
-        case SDLK_k:
-            return KI_K;
-            break;
-        case SDLK_l:
-            return KI_L;
-            break;
-        case SDLK_m:
-            return KI_M;
-            break;
-        case SDLK_n:
-            return KI_N;
-            break;
-        case SDLK_o:
-            return KI_O;
-            break;
-        case SDLK_p:
-            return KI_P;
-            break;
-        case SDLK_q:
-            return KI_Q;
-            break;
-        case SDLK_r:
-            return KI_R;
-            break;
-        case SDLK_s:
-            return KI_S;
-            break;
-        case SDLK_t:
-            return KI_T;
-            break;
-        case SDLK_u:
-            return KI_U;
-            break;
-        case SDLK_v:
-            return KI_V;
-            break;
-        case SDLK_w:
-            return KI_W;
-            break;
-        case SDLK_x:
-            return KI_X;
-            break;
-        case SDLK_y:
-            return KI_Y;
-            break;
-        case SDLK_z:
-            return KI_Z;
-            break;
-        case SDLK_SEMICOLON:
-            return KI_OEM_1;
-            break;
-        case SDLK_PLUS:
-            return KI_OEM_PLUS;
-            break;
-        case SDLK_COMMA:
-            return KI_OEM_COMMA;
-            break;
-        case SDLK_MINUS:
-            return KI_OEM_MINUS;
-            break;
-        case SDLK_PERIOD:
-            return KI_OEM_PERIOD;
-            break;
-        case SDLK_SLASH:
-            return KI_OEM_2;
-            break;
-        case SDLK_BACKQUOTE:
-            return KI_OEM_3;
-            break;
-        case SDLK_LEFTBRACKET:
-            return KI_OEM_4;
-            break;
-        case SDLK_BACKSLASH:
-            return KI_OEM_5;
-            break;
-        case SDLK_RIGHTBRACKET:
-            return KI_OEM_6;
-            break;
-        case SDLK_QUOTEDBL:
-            return KI_OEM_7;
-            break;
-        case SDLK_KP_0:
-            return KI_NUMPAD0;
-            break;
-        case SDLK_KP_1:
-            return KI_NUMPAD1;
-            break;
-        case SDLK_KP_2:
-            return KI_NUMPAD2;
-            break;
-        case SDLK_KP_3:
-            return KI_NUMPAD3;
-            break;
-        case SDLK_KP_4:
-            return KI_NUMPAD4;
-            break;
-        case SDLK_KP_5:
-            return KI_NUMPAD5;
-            break;
-        case SDLK_KP_6:
-            return KI_NUMPAD6;
-            break;
-        case SDLK_KP_7:
-            return KI_NUMPAD7;
-            break;
-        case SDLK_KP_8:
-            return KI_NUMPAD8;
-            break;
-        case SDLK_KP_9:
-            return KI_NUMPAD9;
-            break;
-        case SDLK_KP_ENTER:
-            return KI_NUMPADENTER;
-            break;
-        case SDLK_KP_MULTIPLY:
-            return KI_MULTIPLY;
-            break;
-        case SDLK_KP_PLUS:
-            return KI_ADD;
-            break;
-        case SDLK_KP_MINUS:
-            return KI_SUBTRACT;
-            break;
-        case SDLK_KP_PERIOD:
-            return KI_DECIMAL;
-            break;
-        case SDLK_KP_DIVIDE:
-            return KI_DIVIDE;
-            break;
-        case SDLK_KP_EQUALS:
-            return KI_OEM_NEC_EQUAL;
-            break;
-        case SDLK_BACKSPACE:
-            return KI_BACK;
-            break;
-        case SDLK_TAB:
-            return KI_TAB;
-            break;
-        case SDLK_CLEAR:
-            return KI_CLEAR;
-            break;
-        case SDLK_RETURN:
-            return KI_RETURN;
-            break;
-        case SDLK_PAUSE:
-            return KI_PAUSE;
-            break;
-        case SDLK_CAPSLOCK:
-            return KI_CAPITAL;
-            break;
-        case SDLK_PAGEUP:
-            return KI_PRIOR;
-            break;
-        case SDLK_PAGEDOWN:
-            return KI_NEXT;
-            break;
-        case SDLK_END:
-            return KI_END;
-            break;
-        case SDLK_HOME:
-            return KI_HOME;
-            break;
-        case SDLK_LEFT:
-            return KI_LEFT;
-            break;
-        case SDLK_UP:
-            return KI_UP;
-            break;
-        case SDLK_RIGHT:
-            return KI_RIGHT;
-            break;
-        case SDLK_DOWN:
-            return KI_DOWN;
-            break;
-        case SDLK_INSERT:
-            return KI_INSERT;
-            break;
-        case SDLK_DELETE:
-            return KI_DELETE;
-            break;
-        case SDLK_HELP:
-            return KI_HELP;
-            break;
-        case SDLK_F1:
-            return KI_F1;
-            break;
-        case SDLK_F2:
-            return KI_F2;
-            break;
-        case SDLK_F3:
-            return KI_F3;
-            break;
-        case SDLK_F4:
-            return KI_F4;
-            break;
-        case SDLK_F5:
-            return KI_F5;
-            break;
-        case SDLK_F6:
-            return KI_F6;
-            break;
-        case SDLK_F7:
-            return KI_F7;
-            break;
-        case SDLK_F8:
-            return KI_F8;
-            break;
-        case SDLK_F9:
-            return KI_F9;
-            break;
-        case SDLK_F10:
-            return KI_F10;
-            break;
-        case SDLK_F11:
-            return KI_F11;
-            break;
-        case SDLK_F12:
-            return KI_F12;
-            break;
-        case SDLK_F13:
-            return KI_F13;
-            break;
-        case SDLK_F14:
-            return KI_F14;
-            break;
-        case SDLK_F15:
-            return KI_F15;
-            break;
-        case SDLK_NUMLOCKCLEAR:
-            return KI_NUMLOCK;
-            break;
-        case SDLK_SCROLLLOCK:
-            return KI_SCROLL;
-            break;
-        case SDLK_LSHIFT:
-            return KI_LSHIFT;
-            break;
-        case SDLK_RSHIFT:
-            return KI_RSHIFT;
-            break;
-        case SDLK_LCTRL:
-            return KI_LCONTROL;
-            break;
-        case SDLK_RCTRL:
-            return KI_RCONTROL;
-            break;
-        case SDLK_LALT:
-            return KI_LMENU;
-            break;
-        case SDLK_RALT:
-            return KI_RMENU;
-            break;
-        case SDLK_LGUI:
-            return KI_LMETA;
-            break;
-        case SDLK_RGUI:
-            return KI_RMETA;
-            break;
-        /*case SDLK_LSUPER:
-            return KI_LWIN;
-            break;
-        case SDLK_RSUPER:
-            return KI_RWIN;
-            break;*/
-        default:
-            return KI_UNKNOWN;
-            break;
-    }
-}
-
-int RmlUiSDL2SystemInterface::TranslateMouseButton(Uint8 button)
-{
-    switch(button)
-    {
-        case SDL_BUTTON_LEFT:
-            return 0;
-        case SDL_BUTTON_RIGHT:
-            return 1;
-        case SDL_BUTTON_MIDDLE:
-            return 2;
-        default:
-            return 3;
-    }
-}
-
-int RmlUiSDL2SystemInterface::GetKeyModifiers()
-{
-    SDL_Keymod sdlMods = SDL_GetModState();
-
-    int retval = 0;
-
-    if(sdlMods & KMOD_CTRL)
-        retval |= Rml::Input::KM_CTRL;
-
-    if(sdlMods & KMOD_SHIFT)
-        retval |= Rml::Input::KM_SHIFT;
-
-    if(sdlMods & KMOD_ALT)
-        retval |= Rml::Input::KM_ALT;
-
-    return retval;
-}
-
-double RmlUiSDL2SystemInterface::GetElapsedTime()
-{
-	return double(SDL_GetTicks()) / 1000.0;
-}
-
-bool RmlUiSDL2SystemInterface::LogMessage(Rml::Log::Type type, const Rml::String& message)
-{
-	Rml::String Type;
-
-	switch(type)
-	{
-	case Rml::Log::LT_ALWAYS:
-		Type = "[Always]";
-		break;
-	case Rml::Log::LT_ERROR:
-		Type = "[Error]";
-		break;
-	case Rml::Log::LT_ASSERT:
-		Type = "[Assert]";
-		break;
-	case Rml::Log::LT_WARNING:
-		Type = "[Warning]";
-		break;
-	case Rml::Log::LT_INFO:
-		Type = "[Info]";
-		break;
-	case Rml::Log::LT_DEBUG:
-		Type = "[Debug]";
-		break;
-    case Rml::Log::LT_MAX:
-        break;
-	};
-
-	printf("%s - %s\n", Type.c_str(), message.c_str());
-
-	return true;
-}

+ 0 - 46
Samples/basic/sdl2_sdlrenderer/src/SystemInterfaceSDL2.h

@@ -1,46 +0,0 @@
-/*
- * This source file is part of RmlUi, the HTML/CSS Interface Middleware
- *
- * For the latest information, see http://github.com/mikke89/RmlUi
- *
- * Copyright (c) 2008-2010 Nuno Silva
- * Copyright (c) 2019 The RmlUi Team, and contributors
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- * 
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- *
- */
-#ifndef SYSTEMINTEFACESDL2_H
-#define SYSTEMINTEFACESDL2_H
-
-#include <RmlUi/Core/SystemInterface.h>
-#include <RmlUi/Core/Input.h>
-
-#include <SDL.h>
-
-class RmlUiSDL2SystemInterface : public Rml::SystemInterface
-{
-public:
-    Rml::Input::KeyIdentifier TranslateKey(SDL_Keycode sdlkey);
-    int TranslateMouseButton(Uint8 button);
-	int GetKeyModifiers();
-	
-	double GetElapsedTime() override;
-    bool LogMessage(Rml::Log::Type type, const Rml::String& message) override;
-};
-#endif

+ 0 - 175
Samples/basic/sdl2_sdlrenderer/src/main.cpp

@@ -1,175 +0,0 @@
-/*
- * This source file is part of RmlUi, the HTML/CSS Interface Middleware
- *
- * For the latest information, see http://github.com/mikke89/RmlUi
- *
- * Copyright (c) 2008-2010 Nuno Silva
- * Copyright (c) 2019 The RmlUi Team, and contributors
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- * 
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- *
- */
-
-#include <RmlUi/Core.h>
-#include <RmlUi/Core/Input.h>
-#include <RmlUi/Debugger/Debugger.h>
-#include <Shell.h>
-#include <ShellFileInterface.h>
-#include <string.h>
-
-#include "SystemInterfaceSDL2.h"
-#include "RenderInterfaceSDL2.h"
-
-#ifdef RMLUI_PLATFORM_WIN32
-#include <windows.h>
-#endif
-
-#include <SDL.h>
-
-int main(int /*argc*/, char** /*argv*/)
-{
-#ifdef RMLUI_PLATFORM_WIN32
-	AllocConsole();
-#endif
-
-    int window_width = 1024;
-    int window_height = 768;
-
-    SDL_Init( SDL_INIT_VIDEO );
-    SDL_Window * screen = SDL_CreateWindow("RmlUi SDL2 with SDL_Renderer test", 20, 20, window_width, window_height, SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE);
-
-    /*
-     * Force a specific back-end
-    SDL_SetHint(SDL_HINT_RENDER_BATCHING, "1");
-    SDL_SetHint(SDL_HINT_RENDER_DRIVER, "software");
-    SDL_SetHint(SDL_HINT_RENDER_DRIVER, "opengles2");
-    */
-    
-    SDL_Renderer * renderer = SDL_CreateRenderer(screen, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC);
-	
-	RmlUiSDL2Renderer Renderer(renderer, screen);
-	RmlUiSDL2SystemInterface SystemInterface;
-
-	Rml::String root = Shell::FindSamplesRoot();
-	ShellFileInterface FileInterface(root);
-
-	Rml::SetFileInterface(&FileInterface);
-	Rml::SetRenderInterface(&Renderer);
-	Rml::SetSystemInterface(&SystemInterface);
-
-	if (!Rml::Initialise())
-		return 1;
-
-	struct FontFace {
-		Rml::String filename;
-		bool fallback_face;
-	};
-	FontFace font_faces[] = {
-		{ "LatoLatin-Regular.ttf",    false },
-		{ "LatoLatin-Italic.ttf",     false },
-		{ "LatoLatin-Bold.ttf",       false },
-		{ "LatoLatin-BoldItalic.ttf", false },
-		{ "NotoEmoji-Regular.ttf",    true  },
-	};
-
-	for (const FontFace& face : font_faces)
-	{
-		Rml::LoadFontFace("assets/" + face.filename, face.fallback_face);
-	}
-
-	Rml::Context* Context = Rml::CreateContext("default",
-		Rml::Vector2i(window_width, window_height));
-
-	Rml::Debugger::Initialise(Context);
-
-	Rml::ElementDocument* Document = Context->LoadDocument("assets/demo.rml");
-
-	if (Document)
-	{
-		Document->Show();
-		fprintf(stdout, "\nDocument loaded");
-	}
-	else
-	{
-		fprintf(stdout, "\nDocument is nullptr");
-	}
-
-	bool done = false;
-
-	while (!done)
-	{
-		SDL_Event event;
-
-		SDL_SetRenderDrawColor(renderer, 0, 0, 255, 255);
-		SDL_RenderClear(renderer);
-
-		Context->Render();
-		SDL_RenderPresent(renderer);
-
-		while (SDL_PollEvent(&event))
-		{
-			switch (event.type)
-			{
-			case SDL_QUIT:
-				done = true;
-				break;
-
-			case SDL_MOUSEMOTION:
-				Context->ProcessMouseMove(event.motion.x, event.motion.y, SystemInterface.GetKeyModifiers());
-				break;
-			case SDL_MOUSEBUTTONDOWN:
-				Context->ProcessMouseButtonDown(SystemInterface.TranslateMouseButton(event.button.button), SystemInterface.GetKeyModifiers());
-				break;
-
-			case SDL_MOUSEBUTTONUP:
-				Context->ProcessMouseButtonUp(SystemInterface.TranslateMouseButton(event.button.button), SystemInterface.GetKeyModifiers());
-				break;
-
-			case SDL_MOUSEWHEEL:
-				Context->ProcessMouseWheel(float(event.wheel.y), SystemInterface.GetKeyModifiers());
-				break;
-
-			case SDL_KEYDOWN:
-			{
-				// Intercept F8 key stroke to toggle RmlUi's visual debugger tool
-				if (event.key.keysym.sym == SDLK_F8)
-				{
-					Rml::Debugger::SetVisible(!Rml::Debugger::IsVisible());
-					break;
-				}
-
-				Context->ProcessKeyDown(SystemInterface.TranslateKey(event.key.keysym.sym), SystemInterface.GetKeyModifiers());
-				break;
-			}
-
-			default:
-				break;
-			}
-		}
-		Context->Update();
-	}
-
-	Rml::Shutdown();
-
-    SDL_DestroyRenderer(renderer);
-    SDL_DestroyWindow(screen);
-    SDL_Quit();
-
-	return 0;
-}

+ 0 - 308
Samples/basic/sfml2/src/RenderInterfaceSFML.cpp

@@ -1,308 +0,0 @@
-/*
- * This source file is part of RmlUi, the HTML/CSS Interface Middleware
- *
- * For the latest information, see http://github.com/mikke89/RmlUi
- *
- * Copyright (c) 2008-2010 Nuno Silva
- * Copyright (c) 2019 The RmlUi Team, and contributors
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- * 
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- *
- */
-
-#include <RmlUi/Core.h>
-#include "RenderInterfaceSFML.h"
-
-#ifndef GL_CLAMP_TO_EDGE
-#define GL_CLAMP_TO_EDGE 0x812F
-#endif
-
-#ifdef ENABLE_GLEW
-class RmlUiSFMLRendererGeometryHandler
-{
-public:
-	GLuint VertexID, IndexID;
-	int NumVertices;
-	Rml::TextureHandle Texture;
-
-	RmlUiSFMLRendererGeometryHandler() : VertexID(0), IndexID(0), NumVertices(0), Texture(0)
-	{
-	};
-
-	~RmlUiSFMLRendererGeometryHandler()
-	{
-		if(VertexID)
-			glDeleteBuffers(1, &VertexID);
-
-		if(IndexID)
-			glDeleteBuffers(1, &IndexID);
-
-		VertexID = IndexID = 0;
-	};
-};
-#endif
-
-struct RmlUiSFMLRendererVertex
-{
-	sf::Vector2f Position, TexCoord;
-	sf::Color Color;
-};
-
-RmlUiSFMLRenderer::RmlUiSFMLRenderer()
-{
-}
-
-void RmlUiSFMLRenderer::SetWindow(sf::RenderWindow *Window)
-{
-	MyWindow = Window;
-}
-
-sf::RenderWindow *RmlUiSFMLRenderer::GetWindow()
-{
-	return MyWindow;
-}
-
-// Called by RmlUi when it wants to render geometry that it does not wish to optimise.
-void RmlUiSFMLRenderer::RenderGeometry(Rml::Vertex* vertices, int num_vertices, int* indices, int num_indices, const Rml::TextureHandle texture, const Rml::Vector2f& translation)
-{
-	MyWindow->pushGLStates();
-	initViewport();
-
-	glTranslatef(translation.x, translation.y, 0);
-
-	Rml::Vector<Rml::Vector2f> Positions(num_vertices);
-	Rml::Vector<Rml::Colourb> Colors(num_vertices);
-	Rml::Vector<Rml::Vector2f> TexCoords(num_vertices);
-
-	for(int i = 0; i < num_vertices; i++)
-	{
-		Positions[i] = vertices[i].position;
-		Colors[i] = vertices[i].colour;
-		TexCoords[i] = vertices[i].tex_coord;
-	};
-
-	glEnableClientState(GL_VERTEX_ARRAY);
-	glEnableClientState(GL_COLOR_ARRAY);
-	glEnableClientState(GL_TEXTURE_COORD_ARRAY);
-
-	glVertexPointer(2, GL_FLOAT, 0, &Positions[0]);
-	glColorPointer(4, GL_UNSIGNED_BYTE, 0, &Colors[0]);
-	glTexCoordPointer(2, GL_FLOAT, 0, &TexCoords[0]);
-
-	glEnable(GL_BLEND);
-	glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
-
-	sf::Texture *sfTexture = (sf::Texture *)texture;
-
-	if(sfTexture)
-	{
-		sf::Texture::bind(sfTexture);
-	}
-	else
-	{
-		glDisableClientState(GL_TEXTURE_COORD_ARRAY);
-		glBindTexture(GL_TEXTURE_2D, 0);
-	};
-
-	glDrawElements(GL_TRIANGLES, num_indices, GL_UNSIGNED_INT, indices);
-
-	glDisableClientState(GL_VERTEX_ARRAY);
-	glDisableClientState(GL_COLOR_ARRAY);
-	glDisableClientState(GL_TEXTURE_COORD_ARRAY);
-
-	glColor4f(1, 1, 1, 1);
-
-	MyWindow->popGLStates();
-}
-
-// Called by RmlUi when it wants to compile geometry it believes will be static for the forseeable future.		
-Rml::CompiledGeometryHandle RmlUiSFMLRenderer::CompileGeometry(Rml::Vertex* vertices, int num_vertices, int* indices, int num_indices, const Rml::TextureHandle texture)
-{
-#ifdef ENABLE_GLEW
-	Rml::Vector<RmlUiSFMLRendererVertex> Data(num_vertices);
-
-	for(std::size_t i = 0; i < Data.size(); i++)
-	{
-		Data[i].Position = sf::Vector2f(vertices[i].position.x, vertices[i].position.y);
-		Data[i].TexCoord = sf::Vector2f(vertices[i].tex_coord.x, vertices[i].tex_coord.y);
-		Data[i].Color = sf::Color(vertices[i].colour.red, vertices[i].colour.green,
-			vertices[i].colour.blue, vertices[i].colour.alpha);
-	};
-
-	RmlUiSFMLRendererGeometryHandler *Geometry = new RmlUiSFMLRendererGeometryHandler();
-	Geometry->NumVertices = num_indices;
-
-	glGenBuffers(1, &Geometry->VertexID);
-	glBindBuffer(GL_ARRAY_BUFFER, Geometry->VertexID);
-	glBufferData(GL_ARRAY_BUFFER, sizeof(RmlUiSFMLRendererVertex) * num_vertices, &Data[0],
-		GL_STATIC_DRAW);
-
-	glGenBuffers(1, &Geometry->IndexID);
-	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, Geometry->IndexID);
-	glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(int) * num_indices, indices, GL_STATIC_DRAW);
-
-	glBindBuffer(GL_ARRAY_BUFFER, 0);
-
-	Geometry->Texture = texture;
-
-	return (Rml::CompiledGeometryHandle)Geometry;
-#else
-	return (Rml::CompiledGeometryHandle)nullptr;
-#endif
-}
-
-// Called by RmlUi when it wants to render application-compiled geometry.		
-void RmlUiSFMLRenderer::RenderCompiledGeometry(Rml::CompiledGeometryHandle geometry, const Rml::Vector2f& translation)
-{
-#ifdef ENABLE_GLEW
-	RmlUiSFMLRendererGeometryHandler *RealGeometry = (RmlUiSFMLRendererGeometryHandler *)geometry;
-
-	MyWindow->pushGLStates();
-	initViewport();
-
-	glTranslatef(translation.x, translation.y, 0);
-	glEnable(GL_BLEND);
-	glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
-
-	sf::Texture *texture = (sf::Texture *)RealGeometry->Texture;
-
-	if(texture)
-	{
-		sf::Texture::bind(texture);
-	}
-	else
-	{
-		glBindTexture(GL_TEXTURE_2D, 0);
-	};
-
-	glEnable(GL_VERTEX_ARRAY);
-	glEnable(GL_TEXTURE_COORD_ARRAY);
-	glEnable(GL_COLOR_ARRAY);
-
-	glBindBuffer(GL_ARRAY_BUFFER, RealGeometry->VertexID);
-	glVertexPointer(2, GL_FLOAT, sizeof(RmlUiSFMLRendererVertex), (const void*)0);
-	glTexCoordPointer(2, GL_FLOAT, sizeof(RmlUiSFMLRendererVertex), (const void*)sizeof(sf::Vector2f));
-	glColorPointer(4, GL_UNSIGNED_BYTE, sizeof(RmlUiSFMLRendererVertex), (const void*)sizeof(sf::Vector2f[2]));
-
-	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, RealGeometry->IndexID);
-	glDrawElements(GL_TRIANGLES, RealGeometry->NumVertices, GL_UNSIGNED_INT, (const void*)0);
-
-	glBindBuffer(GL_ARRAY_BUFFER, 0);
-
-	glDisable(GL_COLOR_ARRAY);
-	glDisable(GL_TEXTURE_COORD_ARRAY);
-	glDisable(GL_VERTEX_ARRAY);
-
-	glColor4f(1, 1, 1, 1);
-
-	MyWindow->popGLStates();
-#else
-	RMLUI_ASSERT(false);
-#endif
-}
-
-// Called by RmlUi when it wants to release application-compiled geometry.		
-void RmlUiSFMLRenderer::ReleaseCompiledGeometry(Rml::CompiledGeometryHandle geometry)
-{
-#ifdef ENABLE_GLEW
-	delete (RmlUiSFMLRendererGeometryHandler *)geometry;
-#else
-	RMLUI_ASSERT(false);
-#endif
-}
-
-// Called by RmlUi when it wants to enable or disable scissoring to clip content.		
-void RmlUiSFMLRenderer::EnableScissorRegion(bool enable)
-{
-	if (enable)
-		glEnable(GL_SCISSOR_TEST);
-	else
-		glDisable(GL_SCISSOR_TEST);
-}
-
-// Called by RmlUi when it wants to change the scissor region.		
-void RmlUiSFMLRenderer::SetScissorRegion(int x, int y, int width, int height)
-{
-	glScissor(x, MyWindow->getSize().y - (y + height), width, height);
-}
-
-// Called by RmlUi when a texture is required by the library.		
-bool RmlUiSFMLRenderer::LoadTexture(Rml::TextureHandle& texture_handle, Rml::Vector2i& texture_dimensions, const Rml::String& source)
-{
-	Rml::FileInterface* file_interface = Rml::GetFileInterface();
-	Rml::FileHandle file_handle = file_interface->Open(source);
-	if (!file_handle)
-		return false;
-
-	file_interface->Seek(file_handle, 0, SEEK_END);
-	size_t buffer_size = file_interface->Tell(file_handle);
-	file_interface->Seek(file_handle, 0, SEEK_SET);
-	
-	char* buffer = new char[buffer_size];
-	file_interface->Read(buffer, buffer_size, file_handle);
-	file_interface->Close(file_handle);
-
-	sf::Texture *texture = new sf::Texture();
-
-	if(!texture->loadFromMemory(buffer, buffer_size))
-	{
-		delete[] buffer;
-		delete texture;
-
-		return false;
-	};
-	delete[] buffer;
-
-	texture_handle = (Rml::TextureHandle) texture;
-	texture_dimensions = Rml::Vector2i(texture->getSize().x, texture->getSize().y);
-
-	return true;
-}
-
-// Called by RmlUi when a texture is required to be built from an internally-generated sequence of pixels.
-bool RmlUiSFMLRenderer::GenerateTexture(Rml::TextureHandle& texture_handle, const Rml::byte* source, const Rml::Vector2i& source_dimensions)
-{
-	sf::Texture *texture = new sf::Texture();
-
-	if (!texture->create(source_dimensions.x, source_dimensions.y)) {
-		delete texture;
-		return false;
-	}
-
-	texture->update(source, source_dimensions.x, source_dimensions.y, 0, 0);
-	texture_handle = (Rml::TextureHandle)texture;
-
-	return true;
-}
-
-// Called by RmlUi when a loaded texture is no longer required.		
-void RmlUiSFMLRenderer::ReleaseTexture(Rml::TextureHandle texture_handle)
-{
-	delete (sf::Texture *)texture_handle;
-}
-
-void RmlUiSFMLRenderer::initViewport() {
-	glViewport(0, 0, MyWindow->getSize().x, MyWindow->getSize().y);
-
-	glMatrixMode(GL_PROJECTION);
-	glLoadIdentity();
-
-	glOrtho(0, MyWindow->getSize().x, MyWindow->getSize().y, 0, -1, 1);
-	glMatrixMode(GL_MODELVIEW);
-}

+ 0 - 346
Samples/basic/sfml2/src/SystemInterfaceSFML.cpp

@@ -1,346 +0,0 @@
-/*
- * This source file is part of RmlUi, the HTML/CSS Interface Middleware
- *
- * For the latest information, see http://github.com/mikke89/RmlUi
- *
- * Copyright (c) 2008-2010 Nuno Silva
- * Copyright (c) 2019 The RmlUi Team, and contributors
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- * 
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- *
- */
-#include <RmlUi/Core.h>
-#include "SystemInterfaceSFML.h"
-
-int RmlUiSFMLSystemInterface::GetKeyModifiers()
-{
-	int Modifiers = 0;
-
-	if(sf::Keyboard::isKeyPressed(sf::Keyboard::LShift) ||
-		sf::Keyboard::isKeyPressed(sf::Keyboard::RShift))
-		Modifiers |= Rml::Input::KM_SHIFT;
-
-	if(sf::Keyboard::isKeyPressed(sf::Keyboard::LControl) ||
-		sf::Keyboard::isKeyPressed(sf::Keyboard::RControl))
-		Modifiers |= Rml::Input::KM_CTRL;
-
-	if(sf::Keyboard::isKeyPressed(sf::Keyboard::LAlt) ||
-		sf::Keyboard::isKeyPressed(sf::Keyboard::RAlt))
-		Modifiers |= Rml::Input::KM_ALT;
-
-	return Modifiers;
-}
-
-Rml::Input::KeyIdentifier RmlUiSFMLSystemInterface::TranslateKey(sf::Keyboard::Key Key)
-{
-	switch(Key)
-	{
-	case sf::Keyboard::A:
-		return Rml::Input::KI_A;
-		break;
-	case sf::Keyboard::B:
-		return Rml::Input::KI_B;
-		break;
-	case sf::Keyboard::C:
-		return Rml::Input::KI_C;
-		break;
-	case sf::Keyboard::D:
-		return Rml::Input::KI_D;
-		break;
-	case sf::Keyboard::E:
-		return Rml::Input::KI_E;
-		break;
-	case sf::Keyboard::F:
-		return Rml::Input::KI_F;
-		break;
-	case sf::Keyboard::G:
-		return Rml::Input::KI_G;
-		break;
-	case sf::Keyboard::H:
-		return Rml::Input::KI_H;
-		break;
-	case sf::Keyboard::I:
-		return Rml::Input::KI_I;
-		break;
-	case sf::Keyboard::J:
-		return Rml::Input::KI_J;
-		break;
-	case sf::Keyboard::K:
-		return Rml::Input::KI_K;
-		break;
-	case sf::Keyboard::L:
-		return Rml::Input::KI_L;
-		break;
-	case sf::Keyboard::M:
-		return Rml::Input::KI_M;
-		break;
-	case sf::Keyboard::N:
-		return Rml::Input::KI_N;
-		break;
-	case sf::Keyboard::O:
-		return Rml::Input::KI_O;
-		break;
-	case sf::Keyboard::P:
-		return Rml::Input::KI_P;
-		break;
-	case sf::Keyboard::Q:
-		return Rml::Input::KI_Q;
-		break;
-	case sf::Keyboard::R:
-		return Rml::Input::KI_R;
-		break;
-	case sf::Keyboard::S:
-		return Rml::Input::KI_S;
-		break;
-	case sf::Keyboard::T:
-		return Rml::Input::KI_T;
-		break;
-	case sf::Keyboard::U:
-		return Rml::Input::KI_U;
-		break;
-	case sf::Keyboard::V:
-		return Rml::Input::KI_V;
-		break;
-	case sf::Keyboard::W:
-		return Rml::Input::KI_W;
-		break;
-	case sf::Keyboard::X:
-		return Rml::Input::KI_X;
-		break;
-	case sf::Keyboard::Y:
-		return Rml::Input::KI_Y;
-		break;
-	case sf::Keyboard::Z:
-		return Rml::Input::KI_Z;
-		break;
-	case sf::Keyboard::Num0:
-		return Rml::Input::KI_0;
-		break;
-	case sf::Keyboard::Num1:
-		return Rml::Input::KI_1;
-		break;
-	case sf::Keyboard::Num2:
-		return Rml::Input::KI_2;
-		break;
-	case sf::Keyboard::Num3:
-		return Rml::Input::KI_3;
-		break;
-	case sf::Keyboard::Num4:
-		return Rml::Input::KI_4;
-		break;
-	case sf::Keyboard::Num5:
-		return Rml::Input::KI_5;
-		break;
-	case sf::Keyboard::Num6:
-		return Rml::Input::KI_6;
-		break;
-	case sf::Keyboard::Num7:
-		return Rml::Input::KI_7;
-		break;
-	case sf::Keyboard::Num8:
-		return Rml::Input::KI_8;
-		break;
-	case sf::Keyboard::Num9:
-		return Rml::Input::KI_9;
-		break;
-	case sf::Keyboard::Numpad0:
-		return Rml::Input::KI_NUMPAD0;
-		break;
-	case sf::Keyboard::Numpad1:
-		return Rml::Input::KI_NUMPAD1;
-		break;
-	case sf::Keyboard::Numpad2:
-		return Rml::Input::KI_NUMPAD2;
-		break;
-	case sf::Keyboard::Numpad3:
-		return Rml::Input::KI_NUMPAD3;
-		break;
-	case sf::Keyboard::Numpad4:
-		return Rml::Input::KI_NUMPAD4;
-		break;
-	case sf::Keyboard::Numpad5:
-		return Rml::Input::KI_NUMPAD5;
-		break;
-	case sf::Keyboard::Numpad6:
-		return Rml::Input::KI_NUMPAD6;
-		break;
-	case sf::Keyboard::Numpad7:
-		return Rml::Input::KI_NUMPAD7;
-		break;
-	case sf::Keyboard::Numpad8:
-		return Rml::Input::KI_NUMPAD8;
-		break;
-	case sf::Keyboard::Numpad9:
-		return Rml::Input::KI_NUMPAD9;
-		break;
-	case sf::Keyboard::Left:
-		return Rml::Input::KI_LEFT;
-		break;
-	case sf::Keyboard::Right:
-		return Rml::Input::KI_RIGHT;
-		break;
-	case sf::Keyboard::Up:
-		return Rml::Input::KI_UP;
-		break;
-	case sf::Keyboard::Down:
-		return Rml::Input::KI_DOWN;
-		break;
-	case sf::Keyboard::Add:
-		return Rml::Input::KI_ADD;
-		break;
-	case sf::Keyboard::BackSpace:
-		return Rml::Input::KI_BACK;
-		break;
-	case sf::Keyboard::Delete:
-		return Rml::Input::KI_DELETE;
-		break;
-	case sf::Keyboard::Divide:
-		return Rml::Input::KI_DIVIDE;
-		break;
-	case sf::Keyboard::End:
-		return Rml::Input::KI_END;
-		break;
-	case sf::Keyboard::Escape:
-		return Rml::Input::KI_ESCAPE;
-		break;
-	case sf::Keyboard::F1:
-		return Rml::Input::KI_F1;
-		break;
-	case sf::Keyboard::F2:
-		return Rml::Input::KI_F2;
-		break;
-	case sf::Keyboard::F3:
-		return Rml::Input::KI_F3;
-		break;
-	case sf::Keyboard::F4:
-		return Rml::Input::KI_F4;
-		break;
-	case sf::Keyboard::F5:
-		return Rml::Input::KI_F5;
-		break;
-	case sf::Keyboard::F6:
-		return Rml::Input::KI_F6;
-		break;
-	case sf::Keyboard::F7:
-		return Rml::Input::KI_F7;
-		break;
-	case sf::Keyboard::F8:
-		return Rml::Input::KI_F8;
-		break;
-	case sf::Keyboard::F9:
-		return Rml::Input::KI_F9;
-		break;
-	case sf::Keyboard::F10:
-		return Rml::Input::KI_F10;
-		break;
-	case sf::Keyboard::F11:
-		return Rml::Input::KI_F11;
-		break;
-	case sf::Keyboard::F12:
-		return Rml::Input::KI_F12;
-		break;
-	case sf::Keyboard::F13:
-		return Rml::Input::KI_F13;
-		break;
-	case sf::Keyboard::F14:
-		return Rml::Input::KI_F14;
-		break;
-	case sf::Keyboard::F15:
-		return Rml::Input::KI_F15;
-		break;
-	case sf::Keyboard::Home:
-		return Rml::Input::KI_HOME;
-		break;
-	case sf::Keyboard::Insert:
-		return Rml::Input::KI_INSERT;
-		break;
-	case sf::Keyboard::LControl:
-		return Rml::Input::KI_LCONTROL;
-		break;
-	case sf::Keyboard::LShift:
-		return Rml::Input::KI_LSHIFT;
-		break;
-	case sf::Keyboard::Multiply:
-		return Rml::Input::KI_MULTIPLY;
-		break;
-	case sf::Keyboard::Pause:
-		return Rml::Input::KI_PAUSE;
-		break;
-	case sf::Keyboard::RControl:
-		return Rml::Input::KI_RCONTROL;
-		break;
-	case sf::Keyboard::Return:
-		return Rml::Input::KI_RETURN;
-		break;
-	case sf::Keyboard::RShift:
-		return Rml::Input::KI_RSHIFT;
-		break;
-	case sf::Keyboard::Space:
-		return Rml::Input::KI_SPACE;
-		break;
-	case sf::Keyboard::Subtract:
-		return Rml::Input::KI_SUBTRACT;
-		break;
-	case sf::Keyboard::Tab:
-		return Rml::Input::KI_TAB;
-		break;
-	default:
-		break;
-	};
-
-	return Rml::Input::KI_UNKNOWN;
-}
-
-double RmlUiSFMLSystemInterface::GetElapsedTime()
-{
-	return timer.getElapsedTime().asSeconds();
-}
-
-bool RmlUiSFMLSystemInterface::LogMessage(Rml::Log::Type type, const Rml::String& message)
-{
-	Rml::String Type;
-
-	switch(type)
-	{
-	case Rml::Log::LT_ALWAYS:
-		Type = "[Always]";
-		break;
-	case Rml::Log::LT_ERROR:
-		Type = "[Error]";
-		break;
-	case Rml::Log::LT_ASSERT:
-		Type = "[Assert]";
-		break;
-	case Rml::Log::LT_WARNING:
-		Type = "[Warning]";
-		break;
-	case Rml::Log::LT_INFO:
-		Type = "[Info]";
-		break;
-	case Rml::Log::LT_DEBUG:
-		Type = "[Debug]";
-		break;
-	default:
-		break;
-	};
-
-	printf("%s - %s\n", Type.c_str(), message.c_str());
-
-	return true;
-}

+ 0 - 47
Samples/basic/sfml2/src/SystemInterfaceSFML.h

@@ -1,47 +0,0 @@
-/*
- * This source file is part of RmlUi, the HTML/CSS Interface Middleware
- *
- * For the latest information, see http://github.com/mikke89/RmlUi
- *
- * Copyright (c) 2008-2010 Nuno Silva
- * Copyright (c) 2019 The RmlUi Team, and contributors
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- * 
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- *
- */
-#ifndef SYSTEMINTEFACESFML_H
-#define SYSTEMINTEFACESFML_H
-
-#include <RmlUi/Core/SystemInterface.h>
-#include <RmlUi/Core/Input.h>
-#include <SFML/Graphics.hpp>
-
-class RmlUiSFMLSystemInterface : public Rml::SystemInterface
-{
-public:
-	Rml::Input::KeyIdentifier TranslateKey(sf::Keyboard::Key Key);
-	int GetKeyModifiers();
-	
-	double GetElapsedTime() override;
-	bool LogMessage(Rml::Log::Type type, const Rml::String& message) override;
-
-private:
-	sf::Clock timer;
-};
-#endif

+ 0 - 231
Samples/basic/sfml2/src/main.cpp

@@ -1,231 +0,0 @@
-/*
- * This source file is part of RmlUi, the HTML/CSS Interface Middleware
- *
- * For the latest information, see http://github.com/mikke89/RmlUi
- *
- * Copyright (c) 2008-2010 Nuno Silva
- * Copyright (c) 2019 The RmlUi Team, and contributors
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- * 
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- *
- */
-
-/*
- * Modifed 2013 by Megavolt2013 in order to get the SFML2 sample working
- * with the revised libraries of SFML2
- * Please check the comments starting with NOTE in the files "main.cpp" and
- * "RenderInterfaceSFML.h" if you have trouble building this sample
- */
-
-// NOTE: uncomment this only when you want to use the
-// OpenGL Extension Wrangler Library (GLEW)
-//#include <GL/glew.h>
-
-#include <RmlUi/Core.h>
-#include "SystemInterfaceSFML.h"
-#include "RenderInterfaceSFML.h"
-#include <RmlUi/Core/Input.h>
-#include <RmlUi/Debugger/Debugger.h>
-#include <Shell.h>
-#include <ShellFileInterface.h>
-
-#ifdef RMLUI_PLATFORM_WIN32
-#include <windows.h>
-#endif
-
-float multiplier = 1.f;
-
-void updateView(sf::RenderWindow& window, sf::View& view)
-{
-	view.reset(sf::FloatRect(0.f, 0.f, window.getSize().x * multiplier, window.getSize().y * multiplier));
-	window.setView(view);
-}
-
-int main(int /*argc*/, char** /*argv*/)
-{
-#ifdef RMLUI_PLATFORM_WIN32
-	AllocConsole();
-#endif
-
-	int window_width = 1024;
-	int window_height = 768;
-
-	sf::RenderWindow MyWindow(sf::VideoMode(window_width, window_height), "RmlUi with SFML2");
-	MyWindow.setVerticalSyncEnabled(true);
-
-#ifdef ENABLE_GLEW
-	GLenum err = glewInit();
-	if (GLEW_OK != err)
-	{
-		/* Problem: glewInit failed, something is seriously wrong. */
-		fprintf(stderr, "Error: %s\n", glewGetErrorString(err));
-		//...
-	}
-	fprintf(stdout, "Status: Using GLEW %s\n", glewGetString(GLEW_VERSION));
-#endif
-
-	RmlUiSFMLRenderer Renderer;
-	RmlUiSFMLSystemInterface SystemInterface;
-
-	// NOTE: if fonts and rml are not found you'll probably have to adjust
-	// the path information in the string
-	Rml::String root = Shell::FindSamplesRoot();
-	ShellFileInterface FileInterface(root);
-
-	if (!MyWindow.isOpen())
-		return 1;
-
-	sf::View view(sf::FloatRect(0.f, 0.f, (float)MyWindow.getSize().x, (float)MyWindow.getSize().y));
-	MyWindow.setView(view);
-
-	Renderer.SetWindow(&MyWindow);
-
-	Rml::SetFileInterface(&FileInterface);
-	Rml::SetRenderInterface(&Renderer);
-	Rml::SetSystemInterface(&SystemInterface);
-
-
-	if (!Rml::Initialise())
-		return 1;
-
-	struct FontFace {
-		Rml::String filename;
-		bool fallback_face;
-	};
-	FontFace font_faces[] = {
-		{ "LatoLatin-Regular.ttf",    false },
-		{ "LatoLatin-Italic.ttf",     false },
-		{ "LatoLatin-Bold.ttf",       false },
-		{ "LatoLatin-BoldItalic.ttf", false },
-		{ "NotoEmoji-Regular.ttf",    true  },
-	};
-
-	for (const FontFace& face : font_faces)
-	{
-		Rml::LoadFontFace("assets/" + face.filename, face.fallback_face);
-	}
-	
-	Rml::Context* Context = Rml::CreateContext("default",
-		Rml::Vector2i(MyWindow.getSize().x, MyWindow.getSize().y));
-
-	Rml::Debugger::Initialise(Context);
-
-	Rml::ElementDocument* Document = Context->LoadDocument("assets/demo.rml");
-
-	if (Document)
-	{
-		Document->Show();
-		fprintf(stdout, "\nDocument loaded");
-	}
-	else
-	{
-		fprintf(stdout, "\nDocument is nullptr");
-	}
-
-	while (MyWindow.isOpen())
-	{
-		static sf::Event event;
-
-		MyWindow.clear();
-
-		sf::CircleShape circle(50.f);
-		circle.setPosition(100.f, 100.f);
-		circle.setFillColor(sf::Color::Blue);
-		circle.setOutlineColor(sf::Color::Red);
-		circle.setOutlineThickness(10.f);
-
-		MyWindow.draw(circle);
-
-		Context->Render();
-		MyWindow.display();
-
-		while (MyWindow.pollEvent(event))
-		{
-			switch (event.type)
-			{
-			case sf::Event::Resized:
-				updateView(MyWindow, view);
-				break;
-			case sf::Event::MouseMoved:
-				Context->ProcessMouseMove(event.mouseMove.x, event.mouseMove.y,
-					SystemInterface.GetKeyModifiers());
-				break;
-			case sf::Event::MouseButtonPressed:
-				Context->ProcessMouseButtonDown(event.mouseButton.button,
-					SystemInterface.GetKeyModifiers());
-				break;
-			case sf::Event::MouseButtonReleased:
-				Context->ProcessMouseButtonUp(event.mouseButton.button,
-					SystemInterface.GetKeyModifiers());
-				break;
-			case sf::Event::MouseWheelMoved:
-				Context->ProcessMouseWheel(float(-event.mouseWheel.delta),
-					SystemInterface.GetKeyModifiers());
-				break;
-			case sf::Event::TextEntered:
-				if (event.text.unicode > 32)
-					Context->ProcessTextInput(Rml::Character(event.text.unicode));
-				break;
-			case sf::Event::KeyPressed:
-				Context->ProcessKeyDown(SystemInterface.TranslateKey(event.key.code),
-					SystemInterface.GetKeyModifiers());
-				break;
-			case sf::Event::KeyReleased:
-				switch (event.key.code)
-				{
-				case sf::Keyboard::Num1:
-					multiplier = 2.f;
-					updateView(MyWindow, view);
-					break;
-				case sf::Keyboard::Num2:
-					multiplier = 1.f;
-					updateView(MyWindow, view);
-					break;
-				case sf::Keyboard::Num3:
-					multiplier = .5f;
-					updateView(MyWindow, view);
-					break;
-				case sf::Keyboard::F8:
-					Rml::Debugger::SetVisible(!Rml::Debugger::IsVisible());
-					break;
-				case sf::Keyboard::Escape:
-					MyWindow.close();
-					break;
-				default:
-					break;
-				}
-
-				Context->ProcessKeyUp(SystemInterface.TranslateKey(event.key.code),
-					SystemInterface.GetKeyModifiers());
-				break;
-			case sf::Event::Closed:
-				MyWindow.close();
-				break;
-			default:
-				break;
-			};
-		};
-
-		Context->Update();
-	};
-
-	Rml::Shutdown();
-
-	return 0;
-}

+ 29 - 47
Samples/basic/svg/src/main.cpp

@@ -28,77 +28,49 @@
 
 #include <RmlUi/Core.h>
 #include <RmlUi/Debugger.h>
-#include <Input.h>
+#include <RmlUi_Backend.h>
 #include <Shell.h>
-#include <ShellRenderInterfaceOpenGL.h>
-
-Rml::Context* context = nullptr;
-
-ShellRenderInterfaceExtensions* shell_renderer;
-
-void GameLoop()
-{
-	context->Update();
-
-	shell_renderer->PrepareRenderBuffer();
-	context->Render();
-	shell_renderer->PresentRenderBuffer();
-}
 
 #if defined RMLUI_PLATFORM_WIN32
-#include <windows.h>
-int APIENTRY WinMain(HINSTANCE RMLUI_UNUSED_PARAMETER(instance_handle), HINSTANCE RMLUI_UNUSED_PARAMETER(previous_instance_handle), char* RMLUI_UNUSED_PARAMETER(command_line), int RMLUI_UNUSED_PARAMETER(command_show))
+	#include <RmlUi_Include_Windows.h>
+int APIENTRY WinMain(HINSTANCE /*instance_handle*/, HINSTANCE /*previous_instance_handle*/, char* /*command_line*/, int /*command_show*/)
 #else
-int main(int RMLUI_UNUSED_PARAMETER(argc), char** RMLUI_UNUSED_PARAMETER(argv))
+int main(int /*argc*/, char** /*argv*/)
 #endif
 {
-#ifdef RMLUI_PLATFORM_WIN32
-	RMLUI_UNUSED(instance_handle);
-	RMLUI_UNUSED(previous_instance_handle);
-	RMLUI_UNUSED(command_line);
-	RMLUI_UNUSED(command_show);
-#else
-	RMLUI_UNUSED(argc);
-	RMLUI_UNUSED(argv);
-#endif
-
 	int window_width = 1024;
 	int window_height = 768;
 
-	ShellRenderInterfaceOpenGL opengl_renderer;
-	shell_renderer = &opengl_renderer;
+	// Initializes the shell which provides common functionality used by the included samples.
+	if (!Shell::Initialize())
+		return -1;
 
-	// Generic OS initialisation, creates a window and attaches OpenGL.
-	if (!Shell::Initialise() ||
-		!Shell::OpenWindow("SVG sample", shell_renderer, window_width, window_height, true))
+	// Constructs the system and render interfaces, creates a window, and attaches the renderer.
+	if (!Backend::Initialize("SVG sample", window_width, window_height, true))
 	{
 		Shell::Shutdown();
 		return -1;
 	}
 
-	// RmlUi initialisation.
-	Rml::SetRenderInterface(&opengl_renderer);
-	shell_renderer->SetViewport(window_width, window_height);
-
-	ShellSystemInterface system_interface;
-	Rml::SetSystemInterface(&system_interface);
+	// Install the custom interfaces constructed by the backend before initializing RmlUi.
+	Rml::SetSystemInterface(Backend::GetSystemInterface());
+	Rml::SetRenderInterface(Backend::GetRenderInterface());
 
+	// RmlUi initialisation.
 	Rml::Initialise();
 
-	// Create the main RmlUi context and set it on the shell's input layer.
-	context = Rml::CreateContext("main", Rml::Vector2i(window_width, window_height));
+	// Create the main RmlUi context.
+	Rml::Context* context = Rml::CreateContext("main", Rml::Vector2i(window_width, window_height));
 	if (context == nullptr)
 	{
 		Rml::Shutdown();
+		Backend::Shutdown();
 		Shell::Shutdown();
 		return -1;
 	}
 
 	Rml::Debugger::Initialise(context);
-	Input::SetContext(context);
-	Shell::SetContext(context);
-
-	Shell::LoadFonts("assets/");
+	Shell::LoadFonts();
 
 	// Load and show the demo document.
 	if (Rml::ElementDocument* document = context->LoadDocument("basic/svg/data/svg.rml"))
@@ -107,12 +79,22 @@ int main(int RMLUI_UNUSED_PARAMETER(argc), char** RMLUI_UNUSED_PARAMETER(argv))
 		document->GetElementById("title")->SetInnerRML("SVG");
 	}
 
-	Shell::EventLoop(GameLoop);
+	bool running = true;
+	while (running)
+	{
+		running = Backend::ProcessEvents(context, &Shell::ProcessKeyDownShortcuts);
+
+		context->Update();
+
+		Backend::BeginFrame();
+		context->Render();
+		Backend::PresentFrame();
+	}
 
 	// Shutdown RmlUi.
 	Rml::Shutdown();
 
-	Shell::CloseWindow();
+	Backend::Shutdown();
 	Shell::Shutdown();
 
 	return 0;

+ 56 - 81
Samples/basic/transform/src/main.cpp

@@ -28,10 +28,8 @@
 
 #include <RmlUi/Core.h>
 #include <RmlUi/Debugger.h>
-#include <Input.h>
+#include <RmlUi_Backend.h>
 #include <Shell.h>
-#include <ShellRenderInterfaceOpenGL.h>
-
 #include <cmath>
 #include <sstream>
 
@@ -94,7 +92,7 @@ public:
 			}
 			else if (key_identifier == Rml::Input::KI_ESCAPE)
 			{
-				Shell::RequestExit();
+				Backend::RequestExit();
 			}
 		}
 	}
@@ -104,115 +102,92 @@ private:
 	Rml::ElementDocument *document;
 };
 
-Rml::Context* context = nullptr;
-ShellRenderInterfaceExtensions* shell_renderer;
-DemoWindow* window_1 = nullptr;
-DemoWindow* window_2 = nullptr;
-
-void GameLoop()
-{
-	context->Update();
-
-	shell_renderer->PrepareRenderBuffer();
-	context->Render();
-	shell_renderer->PresentRenderBuffer();
-
-	double t = Rml::GetSystemInterface()->GetElapsedTime();
-	static double t_prev = t;
-	double dt = t - t_prev;
-	t_prev = t;
-
-	if(run_rotate)
-	{
-		static float deg = 0;
-		deg = (float)std::fmod(deg + dt * 50.0, 360.0);
-		if (window_1)
-			window_1->SetRotation(deg);
-		if (window_2)
-			window_2->SetRotation(deg);
-	}
-}
-
 #if defined RMLUI_PLATFORM_WIN32
-#include <windows.h>
-int APIENTRY WinMain(HINSTANCE RMLUI_UNUSED_PARAMETER(instance_handle), HINSTANCE RMLUI_UNUSED_PARAMETER(previous_instance_handle), char* RMLUI_UNUSED_PARAMETER(command_line), int RMLUI_UNUSED_PARAMETER(command_show))
+	#include <RmlUi_Include_Windows.h>
+int APIENTRY WinMain(HINSTANCE /*instance_handle*/, HINSTANCE /*previous_instance_handle*/, char* /*command_line*/, int /*command_show*/)
 #else
-int main(int RMLUI_UNUSED_PARAMETER(argc), char** RMLUI_UNUSED_PARAMETER(argv))
+int main(int /*argc*/, char** /*argv*/)
 #endif
 {
-#ifdef RMLUI_PLATFORM_WIN32
-	RMLUI_UNUSED(instance_handle);
-	RMLUI_UNUSED(previous_instance_handle);
-	RMLUI_UNUSED(command_line);
-	RMLUI_UNUSED(command_show);
-#else
-	RMLUI_UNUSED(argc);
-	RMLUI_UNUSED(argv);
-#endif
-
-	constexpr int width = 1600;
-	constexpr int height = 950;
+	const int window_width = 1600;
+	const int window_height = 950;
 
-	ShellRenderInterfaceOpenGL opengl_renderer;
-	shell_renderer = &opengl_renderer;
+	// Initializes the shell which provides common functionality used by the included samples.
+	if (!Shell::Initialize())
+		return -1;
 
-	// Generic OS initialisation, creates a window and attaches OpenGL.
-	if (!Shell::Initialise() ||
-		!Shell::OpenWindow("Transform Sample", shell_renderer, width, height, true))
+	// Constructs the system and render interfaces, creates a window, and attaches the renderer.
+	if (!Backend::Initialize("Transform Sample", window_width, window_height, true))
 	{
 		Shell::Shutdown();
 		return -1;
 	}
 
-	// RmlUi initialisation.
-	Rml::SetRenderInterface(&opengl_renderer);
-	opengl_renderer.SetViewport(width, height);
-
-	ShellSystemInterface system_interface;
-	Rml::SetSystemInterface(&system_interface);
+	// Install the custom interfaces constructed by the backend before initializing RmlUi.
+	Rml::SetSystemInterface(Backend::GetSystemInterface());
+	Rml::SetRenderInterface(Backend::GetRenderInterface());
 
+	// RmlUi initialisation.
 	Rml::Initialise();
 
-	// Create the main RmlUi context and set it on the shell's input layer.
-	context = Rml::CreateContext("main", Rml::Vector2i(width, height));
-	if (context == nullptr)
+	// Create the main RmlUi context.
+	Rml::Context* context = Rml::CreateContext("main", Rml::Vector2i(window_width, window_height));
+	if (!context)
 	{
 		Rml::Shutdown();
+		Backend::Shutdown();
 		Shell::Shutdown();
 		return -1;
 	}
 
 	Rml::Debugger::Initialise(context);
-	Input::SetContext(context);
-	Shell::SetContext(context);
+	Shell::LoadFonts();
 
-	Shell::LoadFonts("assets/");
-
-	window_1 = new DemoWindow("Orthographic transform", Rml::Vector2f(120, 180), context);
+	Rml::UniquePtr<DemoWindow> window_1 = Rml::MakeUnique<DemoWindow>("Orthographic transform", Rml::Vector2f(120, 180), context);
 	if (window_1)
-	{
-		context->GetRootElement()->AddEventListener(Rml::EventId::Keydown, window_1);
-	}
-	window_2 = new DemoWindow("Perspective transform", Rml::Vector2f(900, 180), context);
+		context->GetRootElement()->AddEventListener(Rml::EventId::Keydown, window_1.get());
+
+	Rml::UniquePtr<DemoWindow> window_2 = Rml::MakeUnique<DemoWindow>("Perspective transform", Rml::Vector2f(900, 180), context);
 	if (window_2)
-	{
 		window_2->SetPerspective(800);
-	}
-
-	Shell::EventLoop(GameLoop);
 
-	if (window_1)
+	bool running = true;
+	while (running)
 	{
-		context->GetRootElement()->RemoveEventListener(Rml::EventId::Keydown, window_1);
+		running = Backend::ProcessEvents(context, &Shell::ProcessKeyDownShortcuts);
+
+		context->Update();
+
+		Backend::BeginFrame();
+		context->Render();
+		Backend::PresentFrame();
+
+		double t = Rml::GetSystemInterface()->GetElapsedTime();
+		static double t_prev = t;
+		double dt = t - t_prev;
+		t_prev = t;
+
+		if (run_rotate)
+		{
+			static float deg = 0;
+			deg = (float)std::fmod(deg + dt * 50.0, 360.0);
+			if (window_1)
+				window_1->SetRotation(deg);
+			if (window_2)
+				window_2->SetRotation(deg);
+		}
 	}
 
-	delete window_1;
-	delete window_2;
+	if (window_1)
+		context->GetRootElement()->RemoveEventListener(Rml::EventId::Keydown, window_1.get());
+
+	window_1.reset();
+	window_2.reset();
 
 	// Shutdown RmlUi.
 	Rml::Shutdown();
-
-	Shell::CloseWindow();
+	
+	Backend::Shutdown();
 	Shell::Shutdown();
 
 	return 0;

+ 3 - 2
Samples/basic/treeview/src/FileBrowser.cpp

@@ -30,6 +30,7 @@
 #include <RmlUi/Core/Context.h>
 #include <RmlUi/Core/DataModelHandle.h>
 #include <Shell.h>
+#include <PlatformExtensions.h>
 
 namespace FileBrowser {
 
@@ -48,7 +49,7 @@ static Rml::Vector<File> files;
 
 static void BuildTree(const Rml::String& current_directory, int current_depth)
 {
-	const Rml::StringList directories = Shell::ListDirectories(current_directory);
+	const Rml::StringList directories = PlatformExtensions::ListDirectories(current_directory);
 
 	for (const Rml::String& directory : directories)
 	{
@@ -59,7 +60,7 @@ static void BuildTree(const Rml::String& current_directory, int current_depth)
 		BuildTree(next_directory, current_depth + 1);
 	}
 
-	const Rml::StringList filenames = Shell::ListFiles(current_directory);
+	const Rml::StringList filenames = PlatformExtensions::ListFiles(current_directory);
 	for (const Rml::String& filename : filenames)
 	{
 		files.push_back(File(false, current_depth, filename));

+ 35 - 56
Samples/basic/treeview/src/main.cpp

@@ -26,87 +26,56 @@
  *
  */
 
+#include "FileBrowser.h"
 #include <RmlUi/Core.h>
 #include <RmlUi/Debugger.h>
-#include <Input.h>
+#include <PlatformExtensions.h>
+#include <RmlUi_Backend.h>
 #include <Shell.h>
-#include <ShellRenderInterfaceOpenGL.h>
-#include "FileBrowser.h"
-
-Rml::Context* context = nullptr;
-
-ShellRenderInterfaceExtensions *shell_renderer;
-
-void GameLoop()
-{
-	context->Update();
-
-	shell_renderer->PrepareRenderBuffer();
-	context->Render();
-	shell_renderer->PresentRenderBuffer();
-}
 
 #if defined RMLUI_PLATFORM_WIN32
-#include <windows.h>
-int APIENTRY WinMain(HINSTANCE RMLUI_UNUSED_PARAMETER(instance_handle), HINSTANCE RMLUI_UNUSED_PARAMETER(previous_instance_handle), char* RMLUI_UNUSED_PARAMETER(command_line), int RMLUI_UNUSED_PARAMETER(command_show))
+	#include <RmlUi_Include_Windows.h>
+int APIENTRY WinMain(HINSTANCE /*instance_handle*/, HINSTANCE /*previous_instance_handle*/, char* /*command_line*/, int /*command_show*/)
 #else
-int main(int RMLUI_UNUSED_PARAMETER(argc), char** RMLUI_UNUSED_PARAMETER(argv))
+int main(int /*argc*/, char** /*argv*/)
 #endif
 {
-#ifdef RMLUI_PLATFORM_WIN32
-	RMLUI_UNUSED(instance_handle);
-	RMLUI_UNUSED(previous_instance_handle);
-	RMLUI_UNUSED(command_line);
-	RMLUI_UNUSED(command_show);
-#else
-	RMLUI_UNUSED(argc);
-	RMLUI_UNUSED(argv);
-#endif
-
-#ifdef RMLUI_PLATFORM_WIN32
-        AllocConsole();
-#endif
-
-	int window_width = 1024;
-	int window_height = 768;
+	const int window_width = 1024;
+	const int window_height = 768;
 
-	ShellRenderInterfaceOpenGL opengl_renderer;
-	shell_renderer = &opengl_renderer;
+	// Initializes the shell which provides common functionality used by the included samples.
+	if (!Shell::Initialize())
+		return -1;
 
-	// Generic OS initialisation, creates a window and attaches OpenGL.
-	if (!Shell::Initialise() ||
-		!Shell::OpenWindow("Tree View Sample", shell_renderer, window_width, window_height, true))
+	// Constructs the system and render interfaces, creates a window, and attaches the renderer.
+	if (!Backend::Initialize("Tree View Sample", window_width, window_height, true))
 	{
 		Shell::Shutdown();
 		return -1;
 	}
 
-	// RmlUi initialisation.
-	Rml::SetRenderInterface(&opengl_renderer);
-	opengl_renderer.SetViewport(window_width, window_height);
-
-	ShellSystemInterface system_interface;
-	Rml::SetSystemInterface(&system_interface);
+	// Install the custom interfaces constructed by the backend before initializing RmlUi.
+	Rml::SetSystemInterface(Backend::GetSystemInterface());
+	Rml::SetRenderInterface(Backend::GetRenderInterface());
 
+	// RmlUi initialisation.
 	Rml::Initialise();
 
-	// Create the main RmlUi context and set it on the shell's input layer.
-	context = Rml::CreateContext("main", Rml::Vector2i(window_width, window_height));
-	if (context == nullptr)
+	// Create the main RmlUi context.
+	Rml::Context* context = Rml::CreateContext("main", Rml::Vector2i(window_width, window_height));
+	if (!context)
 	{
 		Rml::Shutdown();
+		Backend::Shutdown();
 		Shell::Shutdown();
 		return -1;
 	}
 
 	Rml::Debugger::Initialise(context);
-	Input::SetContext(context);
-	Shell::SetContext(context);
-
-	Shell::LoadFonts("assets/");
+	Shell::LoadFonts();
 
 	// Create the file data source and formatter.
-	const Rml::String root = Shell::FindSamplesRoot();
+	const Rml::String root = PlatformExtensions::FindSamplesRoot();
 	FileBrowser::Initialise(context, root);
 
 	// Load and show the demo document.
@@ -117,11 +86,21 @@ int main(int RMLUI_UNUSED_PARAMETER(argc), char** RMLUI_UNUSED_PARAMETER(argv))
 		document->Show();
 	}
 
-	Shell::EventLoop(GameLoop);
+	bool running = true;
+	while (running)
+	{
+		running = Backend::ProcessEvents(context, &Shell::ProcessKeyDownShortcuts);
+
+		context->Update();
+
+		Backend::BeginFrame();
+		context->Render();
+		Backend::PresentFrame();
+	}
 
 	Rml::Shutdown();
 
-	Shell::CloseWindow();
+	Backend::Shutdown();
 	Shell::Shutdown();
 
 	return 0;

+ 2 - 2
Samples/invaders/data/game.rml

@@ -23,8 +23,8 @@
 			
 			div
 			{
-				height: 47dp;
-				padding: 8dp 0 0 65dp;
+				height: 43dp;
+				padding: 12dp 0 0 72dp;
 				margin: 0 20dp;
 
 				font-size: 20dp;

+ 17 - 26
Samples/invaders/src/DecoratorDefender.cpp

@@ -15,7 +15,7 @@
  *
  * The above copyright notice and this permission notice shall be included in
  * all copies or substantial portions of the Software.
- * 
+ *
  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
@@ -28,13 +28,12 @@
 
 #include "DecoratorDefender.h"
 #include <RmlUi/Core/Element.h>
-#include <RmlUi/Core/Texture.h>
+#include <RmlUi/Core/GeometryUtilities.h>
 #include <RmlUi/Core/Math.h>
-#include <ShellOpenGL.h>
+#include <RmlUi/Core/RenderInterface.h>
+#include <RmlUi/Core/Texture.h>
 
-DecoratorDefender::~DecoratorDefender()
-{
-}
+DecoratorDefender::~DecoratorDefender() {}
 
 bool DecoratorDefender::Initialise(const Rml::Texture& texture)
 {
@@ -66,27 +65,19 @@ void DecoratorDefender::RenderElement(Rml::Element* element, Rml::DecoratorDataH
 {
 	RMLUI_UNUSED(element_data);
 
-	Rml::Vector2f position = element->GetAbsoluteOffset(Rml::Box::PADDING).Round();
-	Rml::Vector2f size = element->GetBox().GetSize(Rml::Box::PADDING).Round();
+	Rml::Vector2f position = element->GetAbsoluteOffset(Rml::Box::PADDING);
+	Rml::Vector2f size = element->GetBox().GetSize(Rml::Box::PADDING);
+	Rml::Math::SnapToPixelGrid(position, size);
 
-	glEnable(GL_TEXTURE_2D);
-	glBindTexture(GL_TEXTURE_2D, (GLuint) GetTexture(image_index)->GetHandle(element->GetRenderInterface()));
-	Rml::Colourb colour = element->GetProperty< Rml::Colourb >("color");
-	glColor4ubv(colour);
-	glBegin(GL_QUADS);
-
-		glVertex2f(position.x, position.y);
-		glTexCoord2f(0, 1);
-
-		glVertex2f(position.x, position.y + size.y);
-		glTexCoord2f(1, 1);
-
-		glVertex2f(position.x + size.x, position.y + size.y);
-		glTexCoord2f(1, 0);
+	if (Rml::RenderInterface* render_interface = element->GetRenderInterface())
+	{
+		Rml::TextureHandle texture = GetTexture(image_index)->GetHandle(render_interface);
+		Rml::Colourb color = element->GetProperty<Rml::Colourb>("color");
 
-		glVertex2f(position.x + size.x, position.y);
-		glTexCoord2f(0, 0);
+		Rml::Vertex vertices[4];
+		int indices[6];
+		Rml::GeometryUtilities::GenerateQuad(vertices, indices, Rml::Vector2f(0.f), size, color);
 
-	glEnd();
-	glColor4ub(255, 255, 255, 255);
+		render_interface->RenderGeometry(vertices, 4, indices, 6, texture, position);
+	}
 }

+ 33 - 21
Samples/invaders/src/DecoratorStarfield.cpp

@@ -27,14 +27,16 @@
  */
 
 #include "DecoratorStarfield.h"
-#include <RmlUi/Core/Math.h>
+#include "GameDetails.h"
+#include "Sprite.h"
+#include <RmlUi/Core/Core.h>
 #include <RmlUi/Core/Element.h>
 #include <RmlUi/Core/ElementUtilities.h>
+#include <RmlUi/Core/GeometryUtilities.h>
+#include <RmlUi/Core/Math.h>
+#include <RmlUi/Core/RenderInterface.h>
+#include <RmlUi/Core/SystemInterface.h>
 #include <Shell.h>
-#include <ShellOpenGL.h>
-#include "GameDetails.h"
-
-float last_update_time = 0.0f;
 
 DecoratorStarfield::~DecoratorStarfield()
 {
@@ -56,8 +58,9 @@ bool DecoratorStarfield::Initialise(int _num_layers, const Rml::Colourb& _top_co
 /// Called on a decorator to generate any required per-element data for a newly decorated element.
 Rml::DecoratorDataHandle DecoratorStarfield::GenerateElementData(Rml::Element* element) const
 {
-	StarField* star_field = new StarField();
+	const double t = Rml::GetSystemInterface()->GetElapsedTime();
 
+	StarField* star_field = new StarField();
 	star_field->star_layers.resize(num_layers);
 
 	for (int i = 0; i < num_layers; i++)
@@ -84,7 +87,7 @@ Rml::DecoratorDataHandle DecoratorStarfield::GenerateElementData(Rml::Element* e
 			}
 		}
 
-		star_field->last_update = Shell::GetElapsedTime();
+		star_field->last_update = t;
 	}
 
 	return reinterpret_cast<Rml::DecoratorDataHandle>(star_field);
@@ -96,39 +99,48 @@ void DecoratorStarfield::ReleaseElementData(Rml::DecoratorDataHandle element_dat
 	delete reinterpret_cast<StarField*>(element_data);
 }
 
+
 // Called to render the decorator on an element.
 void DecoratorStarfield::RenderElement(Rml::Element* element, Rml::DecoratorDataHandle element_data) const
 {
+	const double t = Rml::GetSystemInterface()->GetElapsedTime();
+
 	StarField* star_field = reinterpret_cast<StarField*>(element_data);
-	star_field->Update();
+	star_field->Update(t);
 
 	const float dp_ratio = Rml::ElementUtilities::GetDensityIndependentPixelRatio(element);
 	const float point_size = Rml::Math::RoundUpFloat(2.f * dp_ratio);
 
-	glDisable(GL_TEXTURE_2D);
-	glPointSize(point_size);
-	glBegin(GL_POINTS);
+	Rml::RenderInterface* render_interface = element->GetRenderInterface();
+	if (!render_interface)
+		return;
+
+	int num_stars = 0;
+
+	for (size_t i = 0; i < star_field->star_layers.size(); i++)
+		num_stars += (int)star_field->star_layers[i].stars.size();
+
+	ColoredPointList points;
+	points.reserve(num_stars);
 
 	for (size_t i = 0; i < star_field->star_layers.size(); i++)
 	{
-		glColor4ubv(star_field->star_layers[i].colour);
-		
+		Rml::Colourb color = star_field->star_layers[i].colour;
+
 		for (size_t j = 0; j < star_field->star_layers[i].stars.size(); j++)
 		{
-			glVertex2f(star_field->star_layers[i].stars[j].x, star_field->star_layers[i].stars[j].y);
+			const Rml::Vector2f position = star_field->star_layers[i].stars[j];
+			points.push_back(ColoredPoint{color, position});
 		}
 	}
 
-	glEnd();
-
-	glColor4ub(255, 255, 255, 255);
+	DrawPoints(point_size, points);
 }
 
-void DecoratorStarfield::StarField::Update()
+void DecoratorStarfield::StarField::Update(double t)
 {
-	double time = Shell::GetElapsedTime();
-	float delta_time = float(time - last_update);
-	last_update = time;
+	float delta_time = float(t - last_update);
+	last_update = t;
 
 	if (!GameDetails::GetPaused())
 	{

+ 1 - 1
Samples/invaders/src/DecoratorStarfield.h

@@ -71,7 +71,7 @@ private:
 
 	struct StarField
 	{
-		void Update();
+		void Update(double t);
 		double last_update;
 		Rml::Vector2f dimensions;
 

+ 11 - 14
Samples/invaders/src/Defender.cpp

@@ -28,7 +28,6 @@
 
 #include "Defender.h"
 #include <Shell.h>
-#include <ShellOpenGL.h>
 #include "Game.h"
 #include "GameDetails.h"
 #include "Invader.h"
@@ -63,15 +62,15 @@ Defender::~Defender()
 {
 }
 
-void Defender::Update()
+void Defender::Update(double t)
 {
-	float dt = float(Shell::GetElapsedTime() - defender_frame_start);
+	float dt = float(t - defender_frame_start);
 	if (dt < UPDATE_FREQ)
 		return;
 	
 	dt = Rml::Math::Min(dt, 0.1f);
 
-	defender_frame_start = Shell::GetElapsedTime();	
+	defender_frame_start = t;	
 
 	position.x += (move_direction * dt * MOVEMENT_SPEED);
 
@@ -95,7 +94,7 @@ void Defender::Update()
 		render = !render;
 
 		// Check if we should switch back to our alive state
-		if (float(Shell::GetElapsedTime() - respawn_start) > RESPAWN_TIME)
+		if (float(t - respawn_start) > RESPAWN_TIME)
 		{
 			state = ALIVE;
 			render = true;
@@ -103,18 +102,18 @@ void Defender::Update()
 	}
 }
 
-void Defender::Render(float dp_ratio)
+void Defender::Render(double t, float dp_ratio, Rml::TextureHandle texture)
 {
-	glColor4ubv(GameDetails::GetDefenderColour());
+	Rml::Colourb color = GameDetails::GetDefenderColour();
 
 	// Render our sprite if rendering is enabled
 	if (render)
-		defender_sprite.Render(position, dp_ratio);
+		defender_sprite.Render(position, dp_ratio, color, texture);
 
 	// Update the bullet, doing collision detection
 	if (bullet_in_flight)
 	{
-		bullet_sprite.Render(bullet_position, dp_ratio);
+		bullet_sprite.Render(bullet_position, dp_ratio, color, texture);
 
 		// Check if we hit the shields
 		for (int i = 0; i < game->GetNumShields(); i++)
@@ -130,7 +129,7 @@ void Defender::Render(float dp_ratio)
 		{
 			for (int i = 0; i < game->GetNumInvaders(); i++)
 			{
-				if (game->GetInvader(i)->CheckHit(bullet_position))
+				if (game->GetInvader(i)->CheckHit(t, bullet_position))
 				{
 					bullet_in_flight = false;
 					break;
@@ -138,8 +137,6 @@ void Defender::Render(float dp_ratio)
 			}
 		}
 	}
-
-	glColor4ub(255, 255, 255, 255);
 }
 
 void Defender::StartMove(float direction)
@@ -163,7 +160,7 @@ void Defender::Fire()
 	}
 }
 
-bool Defender::CheckHit(const Rml::Vector2f& check_position)
+bool Defender::CheckHit(double t, const Rml::Vector2f& check_position)
 {	
 	float sprite_width = defender_sprite.dimensions.x;
 	float sprite_height = defender_sprite.dimensions.y;
@@ -178,7 +175,7 @@ bool Defender::CheckHit(const Rml::Vector2f& check_position)
 	{
 		game->RemoveLife();
 		state = RESPAWN;
-		respawn_start = Shell::GetElapsedTime();
+		respawn_start = t;
 
 		return true;
 	}	

+ 3 - 3
Samples/invaders/src/Defender.h

@@ -46,9 +46,9 @@ public:
 	~Defender();
 
 	/// Update the defender state.
-	void Update();
+	void Update(double t);
 	/// Render the defender.
-	void Render(float dp_ratio);
+	void Render(double t, float dp_ratio, Rml::TextureHandle texture);
 
 	/// Move the defender left.
 	void StartMove(float direction);	
@@ -58,7 +58,7 @@ public:
 	void Fire();	
 
 	/// Check if an object at the given position would hit the defender.
-	bool CheckHit(const Rml::Vector2f& position);
+	bool CheckHit(double t, const Rml::Vector2f& position);
 
 private:
 	Game* game;

+ 7 - 5
Samples/invaders/src/ElementGame.cpp

@@ -27,12 +27,14 @@
  */
 
 #include "ElementGame.h"
-#include <RmlUi/Core/Context.h>
-#include <RmlUi/Core/ElementDocument.h>
-#include <RmlUi/Core/Input.h>
 #include "Defender.h"
 #include "EventManager.h"
 #include "Game.h"
+#include <RmlUi/Core/Context.h>
+#include <RmlUi/Core/Core.h>
+#include <RmlUi/Core/ElementDocument.h>
+#include <RmlUi/Core/Input.h>
+#include <RmlUi/Core/SystemInterface.h>
 
 ElementGame::ElementGame(const Rml::String& tag) : Rml::Element(tag)
 {
@@ -87,13 +89,13 @@ void ElementGame::ProcessEvent(Rml::Event& event)
 // Updates the game.
 void ElementGame::OnUpdate()
 {
-	game->Update();
+	game->Update(Rml::GetSystemInterface()->GetElapsedTime());
 }
 
 // Renders the game.
 void ElementGame::OnRender()
 {
-	game->Render(GetContext()->GetDensityIndependentPixelRatio());
+	game->Render(Rml::GetSystemInterface()->GetElapsedTime(), GetContext()->GetDensityIndependentPixelRatio());
 }
 
 void ElementGame::OnChildAdd(Rml::Element* element)

+ 4 - 3
Samples/invaders/src/EventManager.cpp

@@ -27,12 +27,13 @@
  */
 
 #include "EventManager.h"
+#include "EventHandler.h"
+#include "GameDetails.h"
 #include <RmlUi/Core/Context.h>
 #include <RmlUi/Core/ElementDocument.h>
 #include <RmlUi/Core/ElementUtilities.h>
+#include <RmlUi_Backend.h>
 #include <Shell.h>
-#include "EventHandler.h"
-#include "GameDetails.h"
 
 // The game's element context (declared in main.cpp).
 extern Rml::Context* context;
@@ -114,7 +115,7 @@ void EventManager::ProcessEvent(Rml::Event& event, const Rml::String& value)
 		}
 		else if (values[0] == "exit")
 		{
-			Shell::RequestExit();
+			Backend::RequestExit();
 		}
 		else if (values[0] == "pause")
 		{

+ 8 - 20
Samples/invaders/src/Game.cpp

@@ -29,7 +29,6 @@
 #include "Game.h"
 #include <RmlUi/Core.h>
 #include <Shell.h>
-#include <ShellOpenGL.h>
 #include "Defender.h"
 #include "EventManager.h"
 #include "GameDetails.h"
@@ -119,7 +118,7 @@ void Game::Initialise()
 	initialized = true;
 }
 
-void Game::Update()
+void Game::Update(double t)
 {
 	if (!GameDetails::GetPaused() && initialized)
 	{
@@ -127,46 +126,35 @@ void Game::Update()
 			return;
 
 		// Determine if we should advance the invaders
-		if (Shell::GetElapsedTime() - invader_frame_start >= invader_move_freq)
+		if (t - invader_frame_start >= invader_move_freq)
 		{
 			MoveInvaders();		
 
-			invader_frame_start = Shell::GetElapsedTime();
+			invader_frame_start = t;
 		}
 
 		// Update all invaders
 		for (int i = 0; i < NUM_INVADERS + 1; i++)
-			invaders[i]->Update();	
+			invaders[i]->Update(t);	
 
-		defender->Update();
+		defender->Update(t);
 	}
 }
 
-void Game::Render(float dp_ratio)
+void Game::Render(double t, float dp_ratio)
 {	
 	if (defender_lives <= 0)
 		return;
 
 	// Render all available shields
 	for (int i = 0; i < NUM_SHIELDS; i++)
-	{
 		shields[i]->Render(dp_ratio);
-	}
-
-	glEnable(GL_TEXTURE_2D);
-	glBindTexture(GL_TEXTURE_2D, (GLuint) texture);
-	glColor4ub(255, 255, 255, 255);
-	glBegin(GL_QUADS);
 
 	// Render all available invaders
 	for (int i = 0; i < NUM_INVADERS + 1; i++)
-	{
-		invaders[i]->Render(dp_ratio);
-	}
+		invaders[i]->Render(dp_ratio, texture);
 	
-	defender->Render(dp_ratio);
-
-	glEnd();
+	defender->Render(t, dp_ratio, texture);
 }
 
 Defender* Game::GetDefender()

+ 2 - 2
Samples/invaders/src/Game.h

@@ -55,10 +55,10 @@ public:
 	void Initialise();
 
 	/// Update the game
-	void Update();
+	void Update(double t);
 
 	/// Render the game
-	void Render(float dp_ratio);
+	void Render(double t, float dp_ratio);
 
 	/// Access the defender
 	Defender* GetDefender();

+ 14 - 21
Samples/invaders/src/Invader.cpp

@@ -29,7 +29,6 @@
 #include "Invader.h"
 #include <RmlUi/Core/Math.h>
 #include <Shell.h>
-#include <ShellOpenGL.h>
 #include "Defender.h"
 #include "Game.h"
 #include "GameDetails.h"
@@ -104,10 +103,10 @@ const Rml::Vector2f& Invader::GetPosition() const
 	return position;
 }
 
-void Invader::Update()
+void Invader::Update(double t)
 {
 	// Update the bombs
-	if (float(Shell::GetElapsedTime() - bomb_frame_start) > BOMB_UPDATE_FREQ)
+	if (float(t - bomb_frame_start) > BOMB_UPDATE_FREQ)
 	{	
 
 		// Update the bomb position if its in flight, or check if we should drop one
@@ -142,7 +141,7 @@ void Invader::Update()
 			// Check if we hit the defender
 			if (bomb != NONE)
 			{
-				if (game->GetDefender()->CheckHit(bomb_position))
+				if (game->GetDefender()->CheckHit(t, bomb_position))
 					bomb = NONE;
 			}
 		}
@@ -160,10 +159,10 @@ void Invader::Update()
 				bomb_animation_frame = 4;
 		}	
 
-		bomb_frame_start = Shell::GetElapsedTime();
+		bomb_frame_start = t;
 	}
 
-	if (state == EXPLODING && Shell::GetElapsedTime() - death_time > 0.0)
+	if (state == EXPLODING && t - death_time > 0.0)
 		state = DEAD;
 }
 
@@ -182,27 +181,21 @@ void Invader::UpdateAnimation()
 	}
 }
 
-void Invader::Render(float dp_ratio)
+void Invader::Render(float dp_ratio, Rml::TextureHandle texture)
 {
+	Rml::Colourb color(255);
+
 	if (type == MOTHERSHIP)
-	{
-		glColor4ubv(MOTHERSHIP_COLOUR);
-	}
+		color = MOTHERSHIP_COLOUR;
+
 	int sprite_index = GetSpriteIndex();
 	int sprite_offset = Rml::Math::RealToInteger((invader_sprites[sprite_index].dimensions.x - 48) / 2);
 
 	if (state != DEAD)
-		invader_sprites[sprite_index].Render(Rml::Vector2f(position.x - sprite_offset, position.y), dp_ratio);
+		invader_sprites[sprite_index].Render(Rml::Vector2f(position.x - sprite_offset, position.y), dp_ratio, color, texture);
 	
 	if (bomb != NONE)
-	{
-		bomb_sprites[bomb_animation_frame].Render(bomb_position, dp_ratio);
-	}
-
-	if (type == MOTHERSHIP)
-	{
-		glColor4ub(255, 255, 255, 255);
-	}
+		bomb_sprites[bomb_animation_frame].Render(bomb_position, dp_ratio, color, texture);
 }
 
 Invader::InvaderState Invader::GetState()
@@ -210,7 +203,7 @@ Invader::InvaderState Invader::GetState()
 	return state;
 }
 
-bool Invader::CheckHit(const Rml::Vector2f& check_position)
+bool Invader::CheckHit(double t, const Rml::Vector2f& check_position)
 {
 	// Get the sprite index we're currently using for collision detection
 	int sprite_index = GetSpriteIndex();
@@ -241,7 +234,7 @@ bool Invader::CheckHit(const Rml::Vector2f& check_position)
 
 		// Set our state to exploding and start the timer to our doom
 		state = EXPLODING;
-		death_time = Shell::GetElapsedTime() + EXPLOSION_TIME;	
+		death_time = t + EXPLOSION_TIME;	
 
 		return true;
 	}

+ 3 - 3
Samples/invaders/src/Invader.h

@@ -57,10 +57,10 @@ public:
 	const Rml::Vector2f& GetPosition() const;
 
 	/// Update the invader
-	virtual void Update();
+	virtual void Update(double t);
 
 	/// Render the invader
-	void Render(float dp_ratio);
+	void Render(float dp_ratio, Rml::TextureHandle texture);
 
 	/// Update the invaders animation
 	void UpdateAnimation();
@@ -75,7 +75,7 @@ public:
 	/// If a hit is detected, will explode and start the death timer
 	/// @param position Position to do the hit check at
 	/// @returns If the invader was hit
-	bool CheckHit(const Rml::Vector2f& position);
+	bool CheckHit(double t, const Rml::Vector2f& position);
 
 protected:
 	// Game this invader is in

+ 4 - 4
Samples/invaders/src/Mothership.cpp

@@ -51,12 +51,12 @@ Mothership::~Mothership()
 {
 }
 
-void Mothership::Update()
+void Mothership::Update(double t)
 {
 	// Generic Invader update
-	Invader::Update();
+	Invader::Update(t);
 
-	if (Shell::GetElapsedTime() - update_frame_start < UPDATE_FREQ)
+	if (t - update_frame_start < UPDATE_FREQ)
 		return;
 
 	// We're alive, keep moving!
@@ -68,7 +68,7 @@ void Mothership::Update()
 			|| (direction > 0.0f && position.x > game->GetWindowDimensions().x))
 			state = DEAD;
 
-		update_frame_start = Shell::GetElapsedTime();
+		update_frame_start = t;
 	}
 	// Determine if we should come out of hiding
 	else if (Rml::Math::RandomReal(1.0f) < APPEARANCE_PROBABILITY)

+ 1 - 1
Samples/invaders/src/Mothership.h

@@ -41,7 +41,7 @@ public:
 	~Mothership();
 
 	/// Update the mothership
-	void Update() override;
+	void Update(double t) override;
 
 private:
 	// Time of the last update

+ 5 - 10
Samples/invaders/src/Shield.cpp

@@ -28,7 +28,6 @@
 
 #include "Shield.h"
 #include <RmlUi/Core/Math.h>
-#include <ShellOpenGL.h>
 #include "Game.h"
 #include "GameDetails.h"
 #include "Sprite.h"
@@ -126,11 +125,9 @@ void Shield::Render(float dp_ratio)
 		const Rml::Vector2f scaled_position = (dp_ratio * position).Round();
 		const int scaled_pixel = Rml::Math::RoundUpToInteger(PIXEL_SIZE * dp_ratio);
 
-		glPointSize((GLfloat)scaled_pixel);
-		glDisable(GL_TEXTURE_2D);
-		glColor4ubv(GameDetails::GetDefenderColour());
-
-		glBegin(GL_POINTS);
+		Rml::Colourb color = GameDetails::GetDefenderColour();
+		ColoredPointList points;
+		points.reserve(NUM_SHIELD_CELLS * NUM_SHIELD_CELLS);
 
 		for (int i = 0; i < NUM_SHIELD_CELLS; i++)
 		{
@@ -139,14 +136,12 @@ void Shield::Render(float dp_ratio)
 				if (shield_cells[i][j] == ON)
 				{
 					Rml::Vector2f cell_position = scaled_position + Rml::Vector2f(float(scaled_pixel * i), float(scaled_pixel * j));
-					glVertex2f(cell_position.x, cell_position.y);
+					points.push_back(ColoredPoint{color, cell_position});
 				}
 			}
 		}
 
-		glEnd();
-
-		glEnable(GL_TEXTURE_2D);
+		DrawPoints((float)scaled_pixel, points);
 	}
 }
 

+ 49 - 18
Samples/invaders/src/Sprite.cpp

@@ -15,7 +15,7 @@
  *
  * The above copyright notice and this permission notice shall be included in
  * all copies or substantial portions of the Software.
- * 
+ *
  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
@@ -27,33 +27,64 @@
  */
 
 #include "Sprite.h"
+#include <RmlUi/Core/Core.h>
+#include <RmlUi/Core/GeometryUtilities.h>
 #include <RmlUi/Core/Math.h>
-#include <ShellOpenGL.h>
+#include <RmlUi/Core/RenderInterface.h>
 
-Sprite::Sprite(const Rml::Vector2f& dimensions, const Rml::Vector2f& top_left_texcoord, const Rml::Vector2f& bottom_right_texcoord) : dimensions(dimensions), top_left_texcoord(top_left_texcoord), bottom_right_texcoord(bottom_right_texcoord)
-{
-}
+Sprite::Sprite(const Rml::Vector2f& dimensions, const Rml::Vector2f& top_left_texcoord, const Rml::Vector2f& bottom_right_texcoord) :
+	dimensions(dimensions), top_left_texcoord(top_left_texcoord), bottom_right_texcoord(bottom_right_texcoord)
+{}
+
+Sprite::~Sprite() {}
 
-Sprite::~Sprite()
+void Sprite::Render(Rml::Vector2f position, const float dp_ratio, Rml::Colourb color, Rml::TextureHandle texture)
 {
+	Rml::RenderInterface* render_interface = Rml::GetRenderInterface();
+	if (!render_interface)
+		return;
+
+	position = dp_ratio * position;
+	Rml::Vector2f dimensions_px = dp_ratio * dimensions;
+	Rml::Math::SnapToPixelGrid(position, dimensions_px);
+
+	Rml::Vertex vertices[4];
+	int indices[6];
+	Rml::GeometryUtilities::GenerateQuad(vertices, indices, Rml::Vector2f(0.f), dimensions_px, color, top_left_texcoord, bottom_right_texcoord);
+
+	render_interface->RenderGeometry(vertices, 4, indices, 6, texture, position);
 }
 
-void Sprite::Render(Rml::Vector2f position, const float dp_ratio)
+void DrawPoints(float point_size, const ColoredPointList& points)
 {
-	position = (dp_ratio * position);
-	Rml::Vector2f dimensions_px = dp_ratio * dimensions;
+	Rml::RenderInterface* render_interface = Rml::GetRenderInterface();
+	if (!render_interface)
+		return;
 
-	Rml::Math::SnapToPixelGrid(position, dimensions_px);
+	constexpr int num_quad_vertices = 4;
+	constexpr int num_quad_indices = 6;
+
+	const int num_points = (int)points.size();
+
+	Rml::Vector<Rml::Vertex> vertices(num_points * num_quad_vertices);
+	Rml::Vector<int> indices(num_points * num_quad_indices);
+
+	int vertex_offset = 0;
+	int index_offset = 0;
 
-	glTexCoord2f(top_left_texcoord.x, top_left_texcoord.y);
-	glVertex2f(position.x, position.y);
+	for (const ColoredPoint& point : points)
+	{
+		Rml::Vector2f position = point.position;
+		Rml::Vector2f size = Rml::Vector2f(point_size);
+		Rml::GeometryUtilities::GenerateQuad(vertices.data() + vertex_offset, indices.data() + index_offset, position, size, point.color,
+			vertex_offset);
 
-	glTexCoord2f(top_left_texcoord.x, bottom_right_texcoord.y);
-	glVertex2f(position.x, position.y + dimensions_px.y);
+		vertex_offset += num_quad_vertices;
+		index_offset += num_quad_indices;
+	}
 
-	glTexCoord2f(bottom_right_texcoord.x, bottom_right_texcoord.y);
-	glVertex2f(position.x + dimensions_px.x, position.y + dimensions_px.y);
+	RMLUI_ASSERT(vertex_offset == (int)vertices.size());
+	RMLUI_ASSERT(index_offset == (int)indices.size());
 
-	glTexCoord2f(bottom_right_texcoord.x, top_left_texcoord.y);
-	glVertex2f(position.x + dimensions_px.x, position.y);
+	render_interface->RenderGeometry(vertices.data(), vertex_offset, indices.data(), index_offset, {}, Rml::Vector2f(0.f));
 }

+ 10 - 3
Samples/invaders/src/Sprite.h

@@ -35,17 +35,24 @@
 	@author Peter Curry
  */
 
-class Sprite
-{
+class Sprite {
 public:
 	Sprite(const Rml::Vector2f& dimensions, const Rml::Vector2f& top_left_texcoord, const Rml::Vector2f& bottom_right_texcoord);
 	~Sprite();
 
-	void Render(Rml::Vector2f position, float dp_ratio);
+	void Render(Rml::Vector2f position, float dp_ratio, Rml::Colourb color, Rml::TextureHandle texture);
 
 	Rml::Vector2f dimensions;
 	Rml::Vector2f top_left_texcoord;
 	Rml::Vector2f bottom_right_texcoord;
 };
 
+struct ColoredPoint {
+	Rml::Colourb color;
+	Rml::Vector2f position;
+};
+using ColoredPointList = Rml::Vector<ColoredPoint>;
+
+void DrawPoints(float point_size, const ColoredPointList& points);
+
 #endif

+ 37 - 57
Samples/invaders/src/main.cpp

@@ -15,7 +15,7 @@
  *
  * The above copyright notice and this permission notice shall be included in
  * all copies or substantial portions of the Software.
- * 
+ *
  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
@@ -26,11 +26,6 @@
  *
  */
 
-#include <RmlUi/Core.h>
-#include <RmlUi/Debugger.h>
-#include <Shell.h>
-#include <ShellRenderInterfaceOpenGL.h>
-#include <Input.h>
 #include "DecoratorInstancerDefender.h"
 #include "DecoratorInstancerStarfield.h"
 #include "ElementGame.h"
@@ -40,83 +35,59 @@
 #include "EventInstancer.h"
 #include "EventManager.h"
 #include "HighScores.h"
+#include <RmlUi/Core.h>
+#include <RmlUi/Debugger.h>
+#include <RmlUi_Backend.h>
+#include <Shell.h>
 
 Rml::Context* context = nullptr;
 
-ShellRenderInterfaceExtensions *shell_renderer;
-
-void GameLoop()
-{
-	context->Update();
-
-	shell_renderer->PrepareRenderBuffer();
-	context->Render();
-	shell_renderer->PresentRenderBuffer();
-}
-
 #if defined RMLUI_PLATFORM_WIN32
-#include <windows.h>
-int APIENTRY WinMain(HINSTANCE RMLUI_UNUSED_PARAMETER(instance_handle), HINSTANCE RMLUI_UNUSED_PARAMETER(previous_instance_handle), char* RMLUI_UNUSED_PARAMETER(command_line), int RMLUI_UNUSED_PARAMETER(command_show))
+	#include <RmlUi_Include_Windows.h>
+int APIENTRY WinMain(HINSTANCE /*instance_handle*/, HINSTANCE /*previous_instance_handle*/, char* /*command_line*/, int /*command_show*/)
 #else
-int main(int RMLUI_UNUSED_PARAMETER(argc), char** RMLUI_UNUSED_PARAMETER(argv))
+int main(int /*argc*/, char** /*argv*/)
 #endif
 {
-#ifdef RMLUI_PLATFORM_WIN32
-	RMLUI_UNUSED(instance_handle);
-	RMLUI_UNUSED(previous_instance_handle);
-	RMLUI_UNUSED(command_line);
-	RMLUI_UNUSED(command_show);
-#else
-	RMLUI_UNUSED(argc);
-	RMLUI_UNUSED(argv);
-#endif
-
-#ifdef RMLUI_PLATFORM_WIN32
-	AllocConsole();
-#endif
-
-	int window_width = 1024;
-	int window_height = 768;
+	const int window_width = 1024;
+	const int window_height = 768;
 
-	ShellRenderInterfaceOpenGL opengl_renderer;
-	shell_renderer = &opengl_renderer;
+	// Initializes the shell which provides common functionality used by the included samples.
+	if (!Shell::Initialize())
+		return -1;
 
-	// Generic OS initialisation, creates a window and attaches OpenGL.
-	if (!Shell::Initialise() ||
-		!Shell::OpenWindow("RmlUi Invaders from Mars", shell_renderer, window_width, window_height, false))
+	// Constructs the system and render interfaces, creates a window, and attaches the renderer.
+	if (!Backend::Initialize("RmlUi Invaders from Mars", window_width, window_height, false))
 	{
 		Shell::Shutdown();
 		return -1;
 	}
 
-	// RmlUi initialisation.
-	Rml::SetRenderInterface(&opengl_renderer);
-	opengl_renderer.SetViewport(window_width, window_height);
-
-	ShellSystemInterface system_interface;
-	Rml::SetSystemInterface(&system_interface);
+	// Install the custom interfaces constructed by the backend before initializing RmlUi.
+	Rml::SetSystemInterface(Backend::GetSystemInterface());
+	Rml::SetRenderInterface(Backend::GetRenderInterface());
 
+	// RmlUi initialisation.
 	Rml::Initialise();
 
-	// Create the main RmlUi context and set it on the shell's input layer.
+	// Create the main RmlUi context.
 	context = Rml::CreateContext("main", Rml::Vector2i(window_width, window_height));
-	if (context == nullptr)
+	if (!context)
 	{
 		Rml::Shutdown();
+		Backend::Shutdown();
 		Shell::Shutdown();
 		return -1;
 	}
 
 	// Initialise the RmlUi debugger.
 	Rml::Debugger::Initialise(context);
-	Input::SetContext(context);
-	Shell::SetContext(context);
 
 	// Load the font faces required for Invaders.
-	Shell::LoadFonts("assets/");
+	Shell::LoadFonts();
 
 	// Register Invader's custom element and decorator instancers.
-	Rml::ElementInstancerGeneric< ElementGame > element_instancer_game;
+	Rml::ElementInstancerGeneric<ElementGame> element_instancer_game;
 	Rml::Factory::RegisterElementInstancer("game", &element_instancer_game);
 
 	DecoratorInstancerStarfield decorator_instancer_starfield;
@@ -136,9 +107,18 @@ int main(int RMLUI_UNUSED_PARAMETER(argc), char** RMLUI_UNUSED_PARAMETER(argv))
 	EventManager::RegisterEventHandler("options", new EventHandlerOptions());
 
 	// Start the game.
-	if (EventManager::LoadWindow("background") &&
-		EventManager::LoadWindow("main_menu"))
-		Shell::EventLoop(GameLoop);
+	bool running = (EventManager::LoadWindow("background") && EventManager::LoadWindow("main_menu"));
+
+	while (running)
+	{
+		running = Backend::ProcessEvents(context, &Shell::ProcessKeyDownShortcuts);
+
+		context->Update();
+
+		Backend::BeginFrame();
+		context->Render();
+		Backend::PresentFrame();
+	}
 
 	// Shut down the game singletons.
 	HighScores::Shutdown();
@@ -149,8 +129,8 @@ int main(int RMLUI_UNUSED_PARAMETER(argc), char** RMLUI_UNUSED_PARAMETER(argv))
 	// Shutdown RmlUi.
 	Rml::Shutdown();
 
-	Shell::CloseWindow();
 	Shell::Shutdown();
+	Backend::Shutdown();
 
 	return 0;
 }

+ 2 - 2
Samples/luainvaders/data/background.rml

@@ -8,7 +8,7 @@
 				z-index: -1;
 			}
 			
-			@decorator star : starfield {
+			@decorator stars : starfield {
 				num-layers: 5;
 				top-colour: #fffc;
 				bottom-colour: #fff3;
@@ -25,7 +25,7 @@
 				height: 100%;
 				z-index: 1;
 
-				decorator: star;
+				decorator: stars;
 			}
 		</style>
 	</head>

+ 3 - 3
Samples/luainvaders/data/game.rml

@@ -22,9 +22,9 @@
 
 			div
 			{
-				height: 47dp;
-				padding: 8dp 0dp 0dp 65dp;
-				margin: 0dp 20dp;
+				height: 43dp;
+				padding: 12dp 0 0 72dp;
+				margin: 0 20dp;
 
 				font-size: 20dp;
 

+ 17 - 26
Samples/luainvaders/src/DecoratorDefender.cpp

@@ -15,7 +15,7 @@
  *
  * The above copyright notice and this permission notice shall be included in
  * all copies or substantial portions of the Software.
- * 
+ *
  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
@@ -28,13 +28,12 @@
 
 #include "DecoratorDefender.h"
 #include <RmlUi/Core/Element.h>
-#include <RmlUi/Core/Texture.h>
+#include <RmlUi/Core/GeometryUtilities.h>
 #include <RmlUi/Core/Math.h>
-#include <ShellOpenGL.h>
+#include <RmlUi/Core/RenderInterface.h>
+#include <RmlUi/Core/Texture.h>
 
-DecoratorDefender::~DecoratorDefender()
-{
-}
+DecoratorDefender::~DecoratorDefender() {}
 
 bool DecoratorDefender::Initialise(const Rml::Texture& texture)
 {
@@ -66,27 +65,19 @@ void DecoratorDefender::RenderElement(Rml::Element* element, Rml::DecoratorDataH
 {
 	RMLUI_UNUSED(element_data);
 
-	Rml::Vector2f position = element->GetAbsoluteOffset(Rml::Box::PADDING).Round();
-	Rml::Vector2f size = element->GetBox().GetSize(Rml::Box::PADDING).Round();
+	Rml::Vector2f position = element->GetAbsoluteOffset(Rml::Box::PADDING);
+	Rml::Vector2f size = element->GetBox().GetSize(Rml::Box::PADDING);
+	Rml::Math::SnapToPixelGrid(position, size);
 
-	glEnable(GL_TEXTURE_2D);
-	glBindTexture(GL_TEXTURE_2D, (GLuint) GetTexture(image_index)->GetHandle(element->GetRenderInterface()));
-	Rml::Colourb colour = element->GetProperty< Rml::Colourb >("color");
-	glColor4ubv(colour);
-	glBegin(GL_QUADS);
-
-		glVertex2f(position.x, position.y);
-		glTexCoord2f(0, 1);
-
-		glVertex2f(position.x, position.y + size.y);
-		glTexCoord2f(1, 1);
-
-		glVertex2f(position.x + size.x, position.y + size.y);
-		glTexCoord2f(1, 0);
+	if (Rml::RenderInterface* render_interface = element->GetRenderInterface())
+	{
+		Rml::TextureHandle texture = GetTexture(image_index)->GetHandle(render_interface);
+		Rml::Colourb color = element->GetProperty<Rml::Colourb>("color");
 
-		glVertex2f(position.x + size.x, position.y);
-		glTexCoord2f(0, 0);
+		Rml::Vertex vertices[4];
+		int indices[6];
+		Rml::GeometryUtilities::GenerateQuad(vertices, indices, Rml::Vector2f(0.f), size, color);
 
-	glEnd();
-	glColor4ub(255, 255, 255, 255);
+		render_interface->RenderGeometry(vertices, 4, indices, 6, texture, position);
+	}
 }

+ 36 - 24
Samples/luainvaders/src/DecoratorStarfield.cpp

@@ -27,14 +27,16 @@
  */
 
 #include "DecoratorStarfield.h"
-#include <RmlUi/Core/Math.h>
+#include "GameDetails.h"
+#include "Sprite.h"
+#include <RmlUi/Core/Core.h>
 #include <RmlUi/Core/Element.h>
 #include <RmlUi/Core/ElementUtilities.h>
+#include <RmlUi/Core/GeometryUtilities.h>
+#include <RmlUi/Core/Math.h>
+#include <RmlUi/Core/RenderInterface.h>
+#include <RmlUi/Core/SystemInterface.h>
 #include <Shell.h>
-#include <ShellOpenGL.h>
-#include "GameDetails.h"
-
-float last_update_time = 0.0f;
 
 DecoratorStarfield::~DecoratorStarfield()
 {
@@ -56,8 +58,9 @@ bool DecoratorStarfield::Initialise(int _num_layers, const Rml::Colourb& _top_co
 /// Called on a decorator to generate any required per-element data for a newly decorated element.
 Rml::DecoratorDataHandle DecoratorStarfield::GenerateElementData(Rml::Element* element) const
 {
-	StarField* star_field = new StarField();
+	const double t = Rml::GetSystemInterface()->GetElapsedTime();
 
+	StarField* star_field = new StarField();
 	star_field->star_layers.resize(num_layers);
 
 	for (int i = 0; i < num_layers; i++)
@@ -84,51 +87,60 @@ Rml::DecoratorDataHandle DecoratorStarfield::GenerateElementData(Rml::Element* e
 			}
 		}
 
-		star_field->last_update = Shell::GetElapsedTime();
+		star_field->last_update = t;
 	}
 
-	return (Rml::DecoratorDataHandle)star_field;
+	return reinterpret_cast<Rml::DecoratorDataHandle>(star_field);
 }
 
 // Called to release element data generated by this decorator.
 void DecoratorStarfield::ReleaseElementData(Rml::DecoratorDataHandle element_data) const
 {
-	delete (StarField*)element_data;
+	delete reinterpret_cast<StarField*>(element_data);
 }
 
+
 // Called to render the decorator on an element.
 void DecoratorStarfield::RenderElement(Rml::Element* element, Rml::DecoratorDataHandle element_data) const
 {
-	StarField* star_field = (StarField*)element_data;
-	star_field->Update();
+	const double t = Rml::GetSystemInterface()->GetElapsedTime();
+
+	StarField* star_field = reinterpret_cast<StarField*>(element_data);
+	star_field->Update(t);
 
 	const float dp_ratio = Rml::ElementUtilities::GetDensityIndependentPixelRatio(element);
 	const float point_size = Rml::Math::RoundUpFloat(2.f * dp_ratio);
 
-	glDisable(GL_TEXTURE_2D);
-	glPointSize(point_size);
-	glBegin(GL_POINTS);
+	Rml::RenderInterface* render_interface = element->GetRenderInterface();
+	if (!render_interface)
+		return;
+
+	int num_stars = 0;
+
+	for (size_t i = 0; i < star_field->star_layers.size(); i++)
+		num_stars += (int)star_field->star_layers[i].stars.size();
+
+	ColoredPointList points;
+	points.reserve(num_stars);
 
 	for (size_t i = 0; i < star_field->star_layers.size(); i++)
 	{
-		glColor4ubv(star_field->star_layers[i].colour);
-		
+		Rml::Colourb color = star_field->star_layers[i].colour;
+
 		for (size_t j = 0; j < star_field->star_layers[i].stars.size(); j++)
 		{
-			glVertex2f(star_field->star_layers[i].stars[j].x, star_field->star_layers[i].stars[j].y);
+			const Rml::Vector2f position = star_field->star_layers[i].stars[j];
+			points.push_back(ColoredPoint{color, position});
 		}
 	}
 
-	glEnd();
-
-	glColor4ub(255, 255, 255, 255);
+	DrawPoints(point_size, points);
 }
 
-void DecoratorStarfield::StarField::Update()
+void DecoratorStarfield::StarField::Update(double t)
 {
-	double time = Shell::GetElapsedTime();
-	float delta_time = float(time - last_update);
-	last_update = time;
+	float delta_time = float(t - last_update);
+	last_update = t;
 
 	if (!GameDetails::GetPaused())
 	{

+ 1 - 1
Samples/luainvaders/src/DecoratorStarfield.h

@@ -71,7 +71,7 @@ private:
 
 	struct StarField
 	{
-		void Update();
+		void Update(double t);
 		double last_update;
 		Rml::Vector2f dimensions;
 

+ 18 - 21
Samples/luainvaders/src/Defender.cpp

@@ -28,7 +28,6 @@
 
 #include "Defender.h"
 #include <Shell.h>
-#include <ShellOpenGL.h>
 #include "Game.h"
 #include "GameDetails.h"
 #include "Invader.h"
@@ -36,11 +35,11 @@
 #include "Shield.h"
 #include "Sprite.h"
 
-static const float UPDATE_FREQ = 0.01f;
-static const float MOVEMENT_SPEED = 300;
-static const float BULLET_SPEED = 15;
-static const int SPRITE_WIDTH = 64;
-static const float RESPAWN_TIME = 1.0f;
+const float UPDATE_FREQ = 0.01f;
+const float MOVEMENT_SPEED = 300;
+const float BULLET_SPEED = 15;
+const int SPRITE_WIDTH = 64;
+const float RESPAWN_TIME = 1.0f;
 
 Sprite defender_sprite(Rml::Vector2f(60, 31), Rml::Vector2f(0, 0.5), Rml::Vector2f(0.23437500, 0.98437500));
 Sprite bullet_sprite(Rml::Vector2f(4, 20), Rml::Vector2f(0.4921875, 0.515625), Rml::Vector2f(0.5078125, 0.828125));
@@ -63,15 +62,15 @@ Defender::~Defender()
 {
 }
 
-void Defender::Update()
+void Defender::Update(double t)
 {
-	float dt = float(Shell::GetElapsedTime() - defender_frame_start);
+	float dt = float(t - defender_frame_start);
 	if (dt < UPDATE_FREQ)
 		return;
-
-	dt = Rml::Math::Min(dt, 0.1f);
 	
-	defender_frame_start = Shell::GetElapsedTime();	
+	dt = Rml::Math::Min(dt, 0.1f);
+
+	defender_frame_start = t;	
 
 	position.x += (move_direction * dt * MOVEMENT_SPEED);
 
@@ -95,7 +94,7 @@ void Defender::Update()
 		render = !render;
 
 		// Check if we should switch back to our alive state
-		if (float(Shell::GetElapsedTime() - respawn_start) > RESPAWN_TIME)
+		if (float(t - respawn_start) > RESPAWN_TIME)
 		{
 			state = ALIVE;
 			render = true;
@@ -103,18 +102,18 @@ void Defender::Update()
 	}
 }
 
-void Defender::Render(float dp_ratio)
+void Defender::Render(double t, float dp_ratio, Rml::TextureHandle texture)
 {
-	glColor4ubv(GameDetails::GetDefenderColour());
+	Rml::Colourb color = GameDetails::GetDefenderColour();
 
 	// Render our sprite if rendering is enabled
 	if (render)
-		defender_sprite.Render(position, dp_ratio);
+		defender_sprite.Render(position, dp_ratio, color, texture);
 
 	// Update the bullet, doing collision detection
 	if (bullet_in_flight)
 	{
-		bullet_sprite.Render(bullet_position, dp_ratio);
+		bullet_sprite.Render(bullet_position, dp_ratio, color, texture);
 
 		// Check if we hit the shields
 		for (int i = 0; i < game->GetNumShields(); i++)
@@ -130,7 +129,7 @@ void Defender::Render(float dp_ratio)
 		{
 			for (int i = 0; i < game->GetNumInvaders(); i++)
 			{
-				if (game->GetInvader(i)->CheckHit(bullet_position))
+				if (game->GetInvader(i)->CheckHit(t, bullet_position))
 				{
 					bullet_in_flight = false;
 					break;
@@ -138,8 +137,6 @@ void Defender::Render(float dp_ratio)
 			}
 		}
 	}
-
-	glColor4ub(255, 255, 255, 255);
 }
 
 void Defender::StartMove(float direction)
@@ -163,7 +160,7 @@ void Defender::Fire()
 	}
 }
 
-bool Defender::CheckHit(const Rml::Vector2f& check_position)
+bool Defender::CheckHit(double t, const Rml::Vector2f& check_position)
 {	
 	float sprite_width = defender_sprite.dimensions.x;
 	float sprite_height = defender_sprite.dimensions.y;
@@ -178,7 +175,7 @@ bool Defender::CheckHit(const Rml::Vector2f& check_position)
 	{
 		game->RemoveLife();
 		state = RESPAWN;
-		respawn_start = Shell::GetElapsedTime();
+		respawn_start = t;
 
 		return true;
 	}	

+ 3 - 3
Samples/luainvaders/src/Defender.h

@@ -46,9 +46,9 @@ public:
 	~Defender();
 
 	/// Update the defender state.
-	void Update();
+	void Update(double t);
 	/// Render the defender.
-	void Render(float dp_ratio);
+	void Render(double t, float dp_ratio, Rml::TextureHandle texture);
 
 	/// Move the defender left.
 	void StartMove(float direction);	
@@ -58,7 +58,7 @@ public:
 	void Fire();	
 
 	/// Check if an object at the given position would hit the defender.
-	bool CheckHit(const Rml::Vector2f& position);
+	bool CheckHit(double t, const Rml::Vector2f& position);
 
 private:
 	Game* game;

+ 7 - 5
Samples/luainvaders/src/ElementGame.cpp

@@ -27,12 +27,14 @@
  */
 
 #include "ElementGame.h"
+#include "Defender.h"
+#include "Game.h"
 #include <RmlUi/Core/Context.h>
+#include <RmlUi/Core/Core.h>
 #include <RmlUi/Core/ElementDocument.h>
-#include <RmlUi/Core/Input.h>
 #include <RmlUi/Core/Factory.h>
-#include "Defender.h"
-#include "Game.h"
+#include <RmlUi/Core/Input.h>
+#include <RmlUi/Core/SystemInterface.h>
 
 ElementGame::ElementGame(const Rml::String& tag) : Rml::Element(tag)
 {
@@ -81,7 +83,7 @@ void ElementGame::ProcessEvent(Rml::Event& event)
 // Updates the game.
 void ElementGame::OnUpdate()
 {
-	game->Update();
+	game->Update(Rml::GetSystemInterface()->GetElapsedTime());
 
 	if (game->IsGameOver())
 		DispatchEvent("gameover", Rml::Dictionary());
@@ -90,7 +92,7 @@ void ElementGame::OnUpdate()
 // Renders the game.
 void ElementGame::OnRender()
 {
-	game->Render(GetContext()->GetDensityIndependentPixelRatio());
+	game->Render(Rml::GetSystemInterface()->GetElapsedTime(), GetContext()->GetDensityIndependentPixelRatio());
 }
 
 void ElementGame::OnChildAdd(Rml::Element* element)

+ 8 - 20
Samples/luainvaders/src/Game.cpp

@@ -29,7 +29,6 @@
 #include "Game.h"
 #include <RmlUi/Core.h>
 #include <Shell.h>
-#include <ShellOpenGL.h>
 #include "Defender.h"
 #include "GameDetails.h"
 #include "HighScores.h"
@@ -117,7 +116,7 @@ void Game::Initialise()
 	InitialiseWave();
 }
 
-void Game::Update()
+void Game::Update(double t)
 {
 	if (!GameDetails::GetPaused())
 	{
@@ -125,46 +124,35 @@ void Game::Update()
 			return;
 
 		// Determine if we should advance the invaders
-		if (Shell::GetElapsedTime() - invader_frame_start >= invader_move_freq)
+		if (t - invader_frame_start >= invader_move_freq)
 		{
 			MoveInvaders();		
 
-			invader_frame_start = Shell::GetElapsedTime();
+			invader_frame_start = t;
 		}
 
 		// Update all invaders
 		for (int i = 0; i < NUM_INVADERS + 1; i++)
-			invaders[i]->Update();	
+			invaders[i]->Update(t);	
 
-		defender->Update();
+		defender->Update(t);
 	}
 }
 
-void Game::Render(float dp_ratio)
+void Game::Render(double t, float dp_ratio)
 {	
 	if (defender_lives <= 0)
 		return;
 
 	// Render all available shields
 	for (int i = 0; i < NUM_SHIELDS; i++)
-	{
 		shields[i]->Render(dp_ratio);
-	}
-
-	glEnable(GL_TEXTURE_2D);
-	glBindTexture(GL_TEXTURE_2D, (GLuint) texture);
-	glColor4ub(255, 255, 255, 255);
-	glBegin(GL_QUADS);
 
 	// Render all available invaders
 	for (int i = 0; i < NUM_INVADERS + 1; i++)
-	{
-		invaders[i]->Render(dp_ratio);
-	}
+		invaders[i]->Render(dp_ratio, texture);
 	
-	defender->Render(dp_ratio);
-
-	glEnd();
+	defender->Render(t, dp_ratio, texture);
 }
 
 Defender* Game::GetDefender()

+ 3 - 3
Samples/luainvaders/src/Game.h

@@ -55,10 +55,10 @@ public:
 	void Initialise();
 
 	/// Update the game
-	void Update();
+	void Update(double t);
 
 	/// Render the game
-	void Render(float dp_ratio);
+	void Render(double t, float dp_ratio);
 
 	/// Access the defender
 	Defender* GetDefender();
@@ -91,7 +91,7 @@ public:
 	bool IsGameOver() const;
 
 	/// Get the dimensions of the game window.
-	const Rml::Vector2f GetWindowDimensions();	
+	const Rml::Vector2f GetWindowDimensions();
 
 private:
 

+ 25 - 32
Samples/luainvaders/src/Invader.cpp

@@ -29,20 +29,19 @@
 #include "Invader.h"
 #include <RmlUi/Core/Math.h>
 #include <Shell.h>
-#include <ShellOpenGL.h>
 #include "Defender.h"
 #include "Game.h"
 #include "GameDetails.h"
 #include "Shield.h"
 #include "Sprite.h"
 
-static const double BOMB_UPDATE_FREQ = 0.04;
-static const float BOMB_RAY_SPEED = 10;
-static const float BOMB_MISSILE_SPEED = 7;
-static const float BOMB_PROBABILITY_EASY = 0.002f;
-static const float BOMB_PROBABILITY_HARD = 0.005f;
-static const float EXPLOSION_TIME = 0.25;
-static const Rml::Colourb MOTHERSHIP_COLOUR = Rml::Colourb(255, 0, 0, 255);
+const float BOMB_UPDATE_FREQ = 0.04f;
+const float BOMB_RAY_SPEED = 10;
+const float BOMB_MISSILE_SPEED = 7;
+const float BOMB_PROBABILITY_EASY = 0.002f;
+const float BOMB_PROBABILITY_HARD = 0.005f;
+const float EXPLOSION_TIME = 0.25f;
+const Rml::Colourb MOTHERSHIP_COLOUR = Rml::Colourb(255, 0, 0, 255);
 
 Sprite invader_sprites[] =
 {
@@ -104,10 +103,10 @@ const Rml::Vector2f& Invader::GetPosition() const
 	return position;
 }
 
-void Invader::Update()
+void Invader::Update(double t)
 {
 	// Update the bombs
-	if (Shell::GetElapsedTime() - bomb_frame_start > BOMB_UPDATE_FREQ)
+	if (float(t - bomb_frame_start) > BOMB_UPDATE_FREQ)
 	{	
 
 		// Update the bomb position if its in flight, or check if we should drop one
@@ -142,13 +141,13 @@ void Invader::Update()
 			// Check if we hit the defender
 			if (bomb != NONE)
 			{
-				if (game->GetDefender()->CheckHit(bomb_position))
+				if (game->GetDefender()->CheckHit(t, bomb_position))
 					bomb = NONE;
 			}
 		}
-		else if (state == ALIVE &&
-				 Rml::Math::RandomReal(1.0f) < bomb_probability &&
-				 game->CanDropBomb(invader_index))
+		else if ( state == ALIVE
+				&& Rml::Math::RandomReal(1.0f) < bomb_probability 
+				&& game->CanDropBomb(invader_index))
 		{
 			bomb = Rml::Math::RandomInteger(2) == 0 ? RAY : MISSILE;
 			bomb_position = position;
@@ -160,10 +159,10 @@ void Invader::Update()
 				bomb_animation_frame = 4;
 		}	
 
-		bomb_frame_start = Shell::GetElapsedTime();
+		bomb_frame_start = t;
 	}
 
-	if (state == EXPLODING && Shell::GetElapsedTime() > death_time)
+	if (state == EXPLODING && t - death_time > 0.0)
 		state = DEAD;
 }
 
@@ -182,27 +181,21 @@ void Invader::UpdateAnimation()
 	}
 }
 
-void Invader::Render(float dp_ratio)
+void Invader::Render(float dp_ratio, Rml::TextureHandle texture)
 {
+	Rml::Colourb color(255);
+
 	if (type == MOTHERSHIP)
-	{
-		glColor4ubv(MOTHERSHIP_COLOUR);
-	}
+		color = MOTHERSHIP_COLOUR;
+
 	int sprite_index = GetSpriteIndex();
 	int sprite_offset = Rml::Math::RealToInteger((invader_sprites[sprite_index].dimensions.x - 48) / 2);
 
 	if (state != DEAD)
-		invader_sprites[sprite_index].Render(Rml::Vector2f(position.x - sprite_offset, position.y), dp_ratio);
+		invader_sprites[sprite_index].Render(Rml::Vector2f(position.x - sprite_offset, position.y), dp_ratio, color, texture);
 	
 	if (bomb != NONE)
-	{
-		bomb_sprites[bomb_animation_frame].Render(bomb_position, dp_ratio);
-	}
-
-	if (type == MOTHERSHIP)
-	{
-		glColor4ub(255, 255, 255, 255);
-	}
+		bomb_sprites[bomb_animation_frame].Render(bomb_position, dp_ratio, color, texture);
 }
 
 Invader::InvaderState Invader::GetState()
@@ -210,7 +203,7 @@ Invader::InvaderState Invader::GetState()
 	return state;
 }
 
-bool Invader::CheckHit(const Rml::Vector2f& check_position)
+bool Invader::CheckHit(double t, const Rml::Vector2f& check_position)
 {
 	// Get the sprite index we're currently using for collision detection
 	int sprite_index = GetSpriteIndex();
@@ -241,7 +234,7 @@ bool Invader::CheckHit(const Rml::Vector2f& check_position)
 
 		// Set our state to exploding and start the timer to our doom
 		state = EXPLODING;
-		death_time = Shell::GetElapsedTime() + EXPLOSION_TIME;	
+		death_time = t + EXPLOSION_TIME;	
 
 		return true;
 	}
@@ -256,7 +249,7 @@ int Invader::GetSpriteIndex() const
 	switch (type)
 	{
 		RMLUI_UNUSED_SWITCH_ENUM(UNKNOWN);
-		case RANK1:                 break;      // animation_frame is the right index already
+		case RANK1: break;	// animation_frame is the right index already
 		case RANK2:	index += 2; break;
 		case RANK3:	index += 4; break;
 		case MOTHERSHIP: index = 6; break;

+ 6 - 6
Samples/luainvaders/src/Invader.h

@@ -41,13 +41,13 @@ class Game;
 
 class Invader
 {
-public:	
+public:
 	enum InvaderType { UNKNOWN, RANK1, RANK2, RANK3, MOTHERSHIP };
 	enum BombType { NONE, RAY, MISSILE };
 
 	/// Construct the invader
 	Invader(Game* game, InvaderType type, int index);
-	virtual ~Invader();	
+	virtual ~Invader();
 
 	/// Set the invaders screen position
 	/// @param position Position in screen space
@@ -57,10 +57,10 @@ public:
 	const Rml::Vector2f& GetPosition() const;
 
 	/// Update the invader
-	virtual void Update();	
+	virtual void Update(double t);
 
 	/// Render the invader
-	void Render(float dp_ratio);
+	void Render(float dp_ratio, Rml::TextureHandle texture);
 
 	/// Update the invaders animation
 	void UpdateAnimation();
@@ -75,7 +75,7 @@ public:
 	/// If a hit is detected, will explode and start the death timer
 	/// @param position Position to do the hit check at
 	/// @returns If the invader was hit
-	bool CheckHit(const Rml::Vector2f& position);
+	bool CheckHit(double t, const Rml::Vector2f& position);
 
 protected:
 	// Game this invader is in
@@ -107,7 +107,7 @@ protected:
 	float bomb_probability;
 
 	// Time when we should die - 0, until we're hit
-	double death_time;	
+	double death_time;
 
 	int GetSpriteIndex() const;
 };

+ 8 - 7
Samples/luainvaders/src/LuaInterface.cpp

@@ -1,14 +1,15 @@
 #include "LuaInterface.h"
-#include <RmlUi/Lua/LuaType.h>
-#include <RmlUi/Lua/IncludeLua.h>
+#include "ElementGameInstancer.h"
 #include "Game.h"
 #include "GameDetails.h"
-#include <RmlUi/Core/Log.h>
-#include <Shell.h>
-#include <RmlUi/Core/Factory.h>
 #include "HighScores.h"
+#include <RmlUi/Core/Factory.h>
+#include <RmlUi/Core/Log.h>
 #include <RmlUi/Core/Types.h>
-#include "ElementGameInstancer.h"
+#include <RmlUi/Lua/IncludeLua.h>
+#include <RmlUi/Lua/LuaType.h>
+#include <RmlUi_Backend.h>
+#include <Shell.h>
 
 //we have to create the binding ourselves, and these are the functions that will be
 //called. It has to match the function signature of int (*ftnptr)(lua_State*)
@@ -73,7 +74,7 @@ void LuaInterface::InitGame(lua_State *L)
 
 int GameShutdown(lua_State* /*L*/)
 {
-    Shell::RequestExit();
+    Backend::RequestExit();
     return 0;
 }
 

Some files were not shown because too many files changed in this diff