diff --git a/.appveyor.yml b/.appveyor.yml index 148db000b..1565c3a97 100644 --- a/.appveyor.yml +++ b/.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 diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index e076d5833..98d7dee1d 100644 --- a/.github/workflows/build.yml +++ b/.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,7 +30,7 @@ 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 @@ -59,12 +59,19 @@ 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 @@ -72,7 +79,9 @@ jobs: - 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 diff --git a/Backends/RmlUi_Backend.h b/Backends/RmlUi_Backend.h new file mode 100644 index 000000000..b03065a35 --- /dev/null +++ b/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 +#include +#include +#include + +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 diff --git a/Backends/RmlUi_Backend_GLFW_GL2.cpp b/Backends/RmlUi_Backend_GLFW_GL2.cpp new file mode 100644 index 000000000..dabe3291f --- /dev/null +++ b/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 +#include +#include +#include + +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 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(); + 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); }); +} diff --git a/Backends/RmlUi_Backend_SDL_GL2.cpp b/Backends/RmlUi_Backend_SDL_GL2.cpp new file mode 100644 index 000000000..6eae74a27 --- /dev/null +++ b/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 +#include +#include +#include +#include +#include + +#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 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(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); +} diff --git a/Backends/RmlUi_Backend_SDL_SDLrenderer.cpp b/Backends/RmlUi_Backend_SDL_SDLrenderer.cpp new file mode 100644 index 000000000..f0a85502d --- /dev/null +++ b/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 +#include +#include +#include + +/** + 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 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(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); +} diff --git a/Backends/RmlUi_Backend_SFML_GL2.cpp b/Backends/RmlUi_Backend_SFML_GL2.cpp new file mode 100644 index 000000000..3813df652 --- /dev/null +++ b/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 +#include +#include +#include +#include +#include +#include + +/** + 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 data; + +bool Backend::Initialize(const char* window_name, int width, int height, bool allow_resize) +{ + RMLUI_ASSERT(!data); + + data = Rml::MakeUnique(); + + // 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; +} diff --git a/Backends/RmlUi_Backend_Win32_GL2.cpp b/Backends/RmlUi_Backend_Win32_GL2.cpp new file mode 100644 index 000000000..fca59420f --- /dev/null +++ b/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 +#include +#include + +/** + 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 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(); + + 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); + } +} \ No newline at end of file diff --git a/Backends/RmlUi_Backend_X11_GL2.cpp b/Backends/RmlUi_Backend_X11_GL2.cpp new file mode 100644 index 000000000..c3d2c0852 --- /dev/null +++ b/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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// 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 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(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); +} diff --git a/Samples/shell/include/macosx/InputMacOSX.h b/Backends/RmlUi_Include_Windows.h similarity index 74% rename from Samples/shell/include/macosx/InputMacOSX.h rename to Backends/RmlUi_Include_Windows.h index 5b23e5b61..90db37da2 100644 --- a/Samples/shell/include/macosx/InputMacOSX.h +++ b/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 +#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 + +#endif #endif diff --git a/Samples/shell/include/x11/X11MacroZapper.h b/Backends/RmlUi_Include_Xlib.h similarity index 78% rename from Samples/shell/include/x11/X11MacroZapper.h rename to Backends/RmlUi_Include_Xlib.h index f831aae77..f308852bb 100644 --- a/Samples/shell/include/x11/X11MacroZapper.h +++ b/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 + + // 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 diff --git a/Backends/RmlUi_Platform_GLFW.cpp b/Backends/RmlUi_Platform_GLFW.cpp new file mode 100644 index 000000000..f0ad90a6e --- /dev/null +++ b/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 +#include +#include +#include +#include + +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; +} \ No newline at end of file diff --git a/Backends/RmlUi_Platform_GLFW.h b/Backends/RmlUi_Platform_GLFW.h new file mode 100644 index 000000000..33b0ad8d4 --- /dev/null +++ b/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 +#include +#include +#include + +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 diff --git a/Backends/RmlUi_Platform_SDL.cpp b/Backends/RmlUi_Platform_SDL.cpp new file mode 100644 index 000000000..580c24db7 --- /dev/null +++ b/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 +#include +#include +#include + +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; +} diff --git a/Samples/shell/include/ShellSystemInterface.h b/Backends/RmlUi_Platform_SDL.h similarity index 55% rename from Samples/shell/include/ShellSystemInterface.h rename to Backends/RmlUi_Platform_SDL.h index 2c19df3b5..c59480a98 100644 --- a/Samples/shell/include/ShellSystemInterface.h +++ b/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 #include +#include +#include -/** - 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 diff --git a/Backends/RmlUi_Platform_SFML.cpp b/Backends/RmlUi_Platform_SFML.cpp new file mode 100644 index 000000000..660dedd5e --- /dev/null +++ b/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 +#include +#include +#include +#include +#include + +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(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; +} diff --git a/Backends/RmlUi_Platform_SFML.h b/Backends/RmlUi_Platform_SFML.h new file mode 100644 index 000000000..0baecf18a --- /dev/null +++ b/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 +#include +#include +#include +#include +#include + +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 diff --git a/Backends/RmlUi_Platform_Win32.cpp b/Backends/RmlUi_Platform_Win32.cpp new file mode 100644 index 000000000..9fcf646d3 --- /dev/null +++ b/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 +#include +#include +#include +#include + +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((short)LOWORD(l_param)), static_cast((short)HIWORD(l_param)), + RmlWin32::GetKeyModifierState()); + break; + case WM_MOUSEWHEEL: + result = context->ProcessMouseWheel(static_cast((short)HIWORD(w_param)) / static_cast(-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; +} diff --git a/Backends/RmlUi_Platform_Win32.h b/Backends/RmlUi_Platform_Win32.h new file mode 100644 index 000000000..a1c8a0215 --- /dev/null +++ b/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 +#include +#include +#include + +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 diff --git a/Backends/RmlUi_Platform_X11.cpp b/Backends/RmlUi_Platform_X11.cpp new file mode 100644 index 000000000..e243b101d --- /dev/null +++ b/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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef HAS_X11XKBLIB + #include +#endif // HAS_X11XKBLIB +#include + +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; +} diff --git a/Backends/RmlUi_Platform_X11.h b/Backends/RmlUi_Platform_X11.h new file mode 100644 index 000000000..f07d428e2 --- /dev/null +++ b/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 +#include +#include +#include + +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 diff --git a/Backends/RmlUi_Renderer_GL2.cpp b/Backends/RmlUi_Renderer_GL2.cpp new file mode 100644 index 000000000..ab37fb8db --- /dev/null +++ b/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 +#include +#include +#include +#include + +#if defined RMLUI_PLATFORM_WIN32 + #include "RmlUi_Include_Windows.h" + #include + #include +#elif defined RMLUI_PLATFORM_MACOSX + #include + #include + #include + #include +#elif defined RMLUI_PLATFORM_UNIX + #include "RmlUi_Include_Xlib.h" + #include + #include + #include + #include +#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::value) + glLoadMatrixf(transform->data()); + else if (std::is_same::value) + glLoadMatrixf(transform->Transpose().data()); + } + else + glLoadIdentity(); +} diff --git a/Samples/basic/sdl2_sdlrenderer/src/RenderInterfaceSDL2.h b/Backends/RmlUi_Renderer_GL2.h similarity index 63% rename from Samples/basic/sdl2_sdlrenderer/src/RenderInterfaceSDL2.h rename to Backends/RmlUi_Renderer_GL2.h index c72153f67..0226b96bb 100644 --- a/Samples/basic/sdl2_sdlrenderer/src/RenderInterfaceSDL2.h +++ b/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 - -#include - -#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 + +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 diff --git a/Backends/RmlUi_Renderer_SDL.cpp b/Backends/RmlUi_Renderer_SDL.cpp new file mode 100644 index 000000000..861926acf --- /dev/null +++ b/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 +#include +#include +#include +#include + +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); +} diff --git a/Samples/basic/sdl2/src/RenderInterfaceSDL2.h b/Backends/RmlUi_Renderer_SDL.h similarity index 64% rename from Samples/basic/sdl2/src/RenderInterfaceSDL2.h rename to Backends/RmlUi_Renderer_SDL.h index 0012d4d36..6bfefa149 100644 --- a/Samples/basic/sdl2/src/RenderInterfaceSDL2.h +++ b/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 - -#include -#include - -#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 +#include + +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 diff --git a/CMake/BackendFileList.cmake b/CMake/BackendFileList.cmake new file mode 100644 index 000000000..24d176f90 --- /dev/null +++ b/CMake/BackendFileList.cmake @@ -0,0 +1,65 @@ +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_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 +) diff --git a/CMake/Modules/FindCarbon.cmake b/CMake/Modules/FindCarbon.cmake deleted file mode 100644 index bae2ee82d..000000000 --- a/CMake/Modules/FindCarbon.cmake +++ /dev/null @@ -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) \ No newline at end of file diff --git a/CMake/Modules/FindSDL2.cmake b/CMake/Modules/FindSDL2.cmake index a3cb4f65f..3f8aeeb96 100644 --- a/CMake/Modules/FindSDL2.cmake +++ b/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 diff --git a/CMake/SampleFileList.cmake b/CMake/SampleFileList.cmake index 7c3a2edaf..5a0ca90cf 100644 --- a/CMake/SampleFileList.cmake +++ b/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() diff --git a/CMake/gen_samplelists.sh b/CMake/gen_samplelists.sh index 70d0ce518..508bd7d4f 100755 --- a/CMake/gen_samplelists.sh +++ b/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 - diff --git a/CMakeLists.txt b/CMakeLists.txt index a101562d0..273ec348a 100644 --- a/CMakeLists.txt +++ b/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,19 @@ 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_SDLrenderer SFML_GL2 GLFW_GL2) + +if(SAMPLES_BACKEND STREQUAL "auto") + if(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) @@ -537,9 +550,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 +565,7 @@ if(DISABLE_RTTI_AND_EXCEPTIONS) endif() else() message(STATUS "Could not create build configuration without rtti and exceptions...") - endif() + endif() endif() @@ -614,7 +627,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 +645,113 @@ 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) + 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) - endif() + 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() - - set(SAMPLES_DIR opt/RmlUi/Samples CACHE PATH "path to samples dir") - if(WIN32) - mark_as_advanced(SAMPLES_DIR) + # 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() - - # 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 "^SDL") + message("-- Looking for SDL2 library for samples backend.") + 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() - - if (WIN32) - target_link_libraries(shell PUBLIC shlwapi) + + 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() - target_link_libraries(shell PUBLIC RmlCore) + 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() - add_common_target_options(shell) - + # 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() endif() @@ -690,6 +759,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 +776,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}) @@ -826,7 +810,7 @@ endif() #=================================== if(RMLUI_TESTS_ENABLED) - add_subdirectory(Tests) + add_subdirectory(Tests) endif() #=================================== diff --git a/Samples/basic/animation/src/main.cpp b/Samples/basic/animation/src/main.cpp index 310a80268..fa705859b 100644 --- a/Samples/basic/animation/src/main.cpp +++ b/Samples/basic/animation/src/main.cpp @@ -27,17 +27,13 @@ */ #include +#include #include -#include +#include #include -#include -#include - #include - -class DemoWindow -{ +class DemoWindow { public: DemoWindow(const Rml::String &title, Rml::Context *context) { @@ -157,62 +153,11 @@ class DemoWindow 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 @@ class Event : public Rml::EventListener { using namespace Rml; - if(value == "exit") - Shell::RequestExit(); + if (value == "exit") + Backend::RequestExit(); switch (event.GetId()) { @@ -250,7 +195,7 @@ class Event : public Rml::EventListener } else if (key_identifier == Rml::Input::KI_ESCAPE) { - Shell::RequestExit(); + Backend::RequestExit(); } else if (key_identifier == Rml::Input::KI_LEFT) { @@ -308,92 +253,112 @@ class Event : public Rml::EventListener 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 -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 +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 window = Rml::MakeUnique("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; diff --git a/Samples/basic/benchmark/src/main.cpp b/Samples/basic/benchmark/src/main.cpp index 7b30f8ec7..c451dd8fc 100644 --- a/Samples/basic/benchmark/src/main.cpp +++ b/Samples/basic/benchmark/src/main.cpp @@ -28,10 +28,8 @@ #include #include -#include +#include #include -#include - class DemoWindow { @@ -116,66 +114,11 @@ class DemoWindow 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 @@ class Event : public Rml::EventListener using namespace Rml; if(value == "exit") - Shell::RequestExit(); + Backend::RequestExit(); if (event == "keydown") { @@ -212,7 +155,7 @@ class Event : public Rml::EventListener } else if (key_identifier == Rml::Input::KI_ESCAPE) { - Shell::RequestExit(); + Backend::RequestExit(); } } } @@ -223,7 +166,6 @@ class Event : public Rml::EventListener Rml::String value; }; - class EventInstancer : public Rml::EventListenerInstancer { public: @@ -235,79 +177,113 @@ class EventInstancer : public Rml::EventListenerInstancer } }; - #if defined RMLUI_PLATFORM_WIN32 -#include -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 +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 window = Rml::MakeUnique("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; diff --git a/Samples/basic/bitmapfont/src/main.cpp b/Samples/basic/bitmapfont/src/main.cpp index 515935fd6..497e56c14 100644 --- a/Samples/basic/bitmapfont/src/main.cpp +++ b/Samples/basic/bitmapfont/src/main.cpp @@ -26,13 +26,11 @@ * */ +#include "FontEngineInterfaceBitmap.h" #include #include -#include +#include #include -#include - -#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 -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 +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(); + 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; diff --git a/Samples/basic/customlog/src/SystemInterface.cpp b/Samples/basic/customlog/src/SystemInterface.cpp index be41be6d7..205500d6c 100644 --- a/Samples/basic/customlog/src/SystemInterface.cpp +++ b/Samples/basic/customlog/src/SystemInterface.cpp @@ -30,9 +30,10 @@ #include #include #include +#include #include #ifdef RMLUI_PLATFORM_WIN32 -#include +#include #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 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 } diff --git a/Samples/basic/customlog/src/main.cpp b/Samples/basic/customlog/src/main.cpp index 5e72dc23c..5b03f743a 100644 --- a/Samples/basic/customlog/src/main.cpp +++ b/Samples/basic/customlog/src/main.cpp @@ -26,90 +26,62 @@ * */ +#include "SystemInterface.h" #include #include -#include +#include #include -#include -#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 -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 +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; diff --git a/Samples/basic/databinding/src/main.cpp b/Samples/basic/databinding/src/main.cpp index b5a7077b8..86e3872a1 100644 --- a/Samples/basic/databinding/src/main.cpp +++ b/Samples/basic/databinding/src/main.cpp @@ -28,12 +28,10 @@ #include #include -#include +#include #include -#include #include - 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 @@ class DemoWindow : public Rml::EventListener } } - void Shutdown() + void Shutdown() { if (document) { @@ -443,95 +439,53 @@ class DemoWindow : public Rml::EventListener { 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("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 -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 +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("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(); diff --git a/Samples/basic/demo/src/main.cpp b/Samples/basic/demo/src/main.cpp index d13af8609..74d27acb9 100644 --- a/Samples/basic/demo/src/main.cpp +++ b/Samples/basic/demo/src/main.cpp @@ -27,12 +27,11 @@ */ #include +#include +#include #include -#include +#include #include -#include -#include -#include 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 @@ class DemoWindow : public Rml::EventListener 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 @@ class DemoWindow : public Rml::EventListener }; -Rml::Context* context = nullptr; -ShellRenderInterfaceExtensions *shell_renderer; Rml::UniquePtr 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 @@ class DemoEventListener : public Rml::EventListener } else if (value == "confirm_exit") { - Shell::RequestExit(); + Backend::RequestExit(); } else if (value == "cancel_exit") { @@ -444,76 +424,74 @@ class DemoEventListenerInstancer : public Rml::EventListenerInstancer #if defined RMLUI_PLATFORM_WIN32 -#include -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 +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("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(); diff --git a/Samples/basic/drag/src/main.cpp b/Samples/basic/drag/src/main.cpp index 9ffce430a..52637225c 100644 --- a/Samples/basic/drag/src/main.cpp +++ b/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 #include -#include +#include #include -#include -#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 -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 +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; diff --git a/Samples/basic/loaddocument/src/main.cpp b/Samples/basic/loaddocument/src/main.cpp index 4e42925a2..4bf71cae5 100644 --- a/Samples/basic/loaddocument/src/main.cpp +++ b/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 #include -#include +#include #include -#include - -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 -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 +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; diff --git a/Samples/basic/lottie/src/main.cpp b/Samples/basic/lottie/src/main.cpp index bf4e49928..2e808ede1 100644 --- a/Samples/basic/lottie/src/main.cpp +++ b/Samples/basic/lottie/src/main.cpp @@ -28,77 +28,49 @@ #include #include -#include +#include #include -#include - -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 -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 +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; diff --git a/Samples/basic/sdl2/src/RenderInterfaceSDL2.cpp b/Samples/basic/sdl2/src/RenderInterfaceSDL2.cpp deleted file mode 100644 index bd7de84e8..000000000 --- a/Samples/basic/sdl2/src/RenderInterfaceSDL2.cpp +++ /dev/null @@ -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 -#include - -#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 Positions(num_vertices); - Rml::Vector Colors(num_vertices); - Rml::Vector 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); -} diff --git a/Samples/basic/sdl2/src/SystemInterfaceSDL2.cpp b/Samples/basic/sdl2/src/SystemInterfaceSDL2.cpp deleted file mode 100644 index 3910ff44e..000000000 --- a/Samples/basic/sdl2/src/SystemInterfaceSDL2.cpp +++ /dev/null @@ -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 -#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; -} diff --git a/Samples/basic/sdl2/src/SystemInterfaceSDL2.h b/Samples/basic/sdl2/src/SystemInterfaceSDL2.h deleted file mode 100644 index b5af61daf..000000000 --- a/Samples/basic/sdl2/src/SystemInterfaceSDL2.h +++ /dev/null @@ -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 -#include - -#include - -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 diff --git a/Samples/basic/sdl2/src/main.cpp b/Samples/basic/sdl2/src/main.cpp deleted file mode 100644 index 88b77d2f5..000000000 --- a/Samples/basic/sdl2/src/main.cpp +++ /dev/null @@ -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 -#include -#include -#include -#include -#include - -#include "SystemInterfaceSDL2.h" -#include "RenderInterfaceSDL2.h" - -#ifdef RMLUI_PLATFORM_WIN32 -#include -#endif - -#include - -#include - -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; -} diff --git a/Samples/basic/sdl2_sdlrenderer/src/RenderInterfaceSDL2.cpp b/Samples/basic/sdl2_sdlrenderer/src/RenderInterfaceSDL2.cpp deleted file mode 100644 index a9d464b79..000000000 --- a/Samples/basic/sdl2_sdlrenderer/src/RenderInterfaceSDL2.cpp +++ /dev/null @@ -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 -#include - -#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); -} diff --git a/Samples/basic/sdl2_sdlrenderer/src/SystemInterfaceSDL2.cpp b/Samples/basic/sdl2_sdlrenderer/src/SystemInterfaceSDL2.cpp deleted file mode 100644 index 3910ff44e..000000000 --- a/Samples/basic/sdl2_sdlrenderer/src/SystemInterfaceSDL2.cpp +++ /dev/null @@ -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 -#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; -} diff --git a/Samples/basic/sdl2_sdlrenderer/src/SystemInterfaceSDL2.h b/Samples/basic/sdl2_sdlrenderer/src/SystemInterfaceSDL2.h deleted file mode 100644 index b5af61daf..000000000 --- a/Samples/basic/sdl2_sdlrenderer/src/SystemInterfaceSDL2.h +++ /dev/null @@ -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 -#include - -#include - -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 diff --git a/Samples/basic/sdl2_sdlrenderer/src/main.cpp b/Samples/basic/sdl2_sdlrenderer/src/main.cpp deleted file mode 100644 index eb69e8e36..000000000 --- a/Samples/basic/sdl2_sdlrenderer/src/main.cpp +++ /dev/null @@ -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 -#include -#include -#include -#include -#include - -#include "SystemInterfaceSDL2.h" -#include "RenderInterfaceSDL2.h" - -#ifdef RMLUI_PLATFORM_WIN32 -#include -#endif - -#include - -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; -} diff --git a/Samples/basic/sfml2/src/RenderInterfaceSFML.cpp b/Samples/basic/sfml2/src/RenderInterfaceSFML.cpp deleted file mode 100644 index 0c887381d..000000000 --- a/Samples/basic/sfml2/src/RenderInterfaceSFML.cpp +++ /dev/null @@ -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 -#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 Positions(num_vertices); - Rml::Vector Colors(num_vertices); - Rml::Vector 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 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); -} diff --git a/Samples/basic/sfml2/src/RenderInterfaceSFML.h b/Samples/basic/sfml2/src/RenderInterfaceSFML.h deleted file mode 100644 index 3682b78db..000000000 --- a/Samples/basic/sfml2/src/RenderInterfaceSFML.h +++ /dev/null @@ -1,90 +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 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 -#endif - -#include -#include - -// 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 - -class RmlUiSFMLRenderer : public Rml::RenderInterface -{ -public: - RmlUiSFMLRenderer(); - - /// Sets the window - void SetWindow(sf::RenderWindow *Window); - - /// Returns the currently assigned window - sf::RenderWindow *GetWindow(); - - /// 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 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; - - /// Called by RmlUi when it wants to render application-compiled geometry. - 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(); - -private: - sf::RenderWindow *MyWindow; -}; - -#endif diff --git a/Samples/basic/sfml2/src/SystemInterfaceSFML.cpp b/Samples/basic/sfml2/src/SystemInterfaceSFML.cpp deleted file mode 100644 index 4b5069d26..000000000 --- a/Samples/basic/sfml2/src/SystemInterfaceSFML.cpp +++ /dev/null @@ -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 -#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; -} diff --git a/Samples/basic/sfml2/src/SystemInterfaceSFML.h b/Samples/basic/sfml2/src/SystemInterfaceSFML.h deleted file mode 100644 index e5969d588..000000000 --- a/Samples/basic/sfml2/src/SystemInterfaceSFML.h +++ /dev/null @@ -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 -#include -#include - -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 diff --git a/Samples/basic/sfml2/src/main.cpp b/Samples/basic/sfml2/src/main.cpp deleted file mode 100644 index 6d88d2c9f..000000000 --- a/Samples/basic/sfml2/src/main.cpp +++ /dev/null @@ -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 - -#include -#include "SystemInterfaceSFML.h" -#include "RenderInterfaceSFML.h" -#include -#include -#include -#include - -#ifdef RMLUI_PLATFORM_WIN32 -#include -#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; -} diff --git a/Samples/basic/svg/src/main.cpp b/Samples/basic/svg/src/main.cpp index 0a6f01eb2..aa19cc7cd 100644 --- a/Samples/basic/svg/src/main.cpp +++ b/Samples/basic/svg/src/main.cpp @@ -28,77 +28,49 @@ #include #include -#include +#include #include -#include - -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 -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 +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; diff --git a/Samples/basic/transform/src/main.cpp b/Samples/basic/transform/src/main.cpp index 2a333d2e1..1098b8956 100644 --- a/Samples/basic/transform/src/main.cpp +++ b/Samples/basic/transform/src/main.cpp @@ -28,10 +28,8 @@ #include #include -#include +#include #include -#include - #include #include @@ -94,7 +92,7 @@ class DemoWindow : public Rml::EventListener } else if (key_identifier == Rml::Input::KI_ESCAPE) { - Shell::RequestExit(); + Backend::RequestExit(); } } } @@ -104,115 +102,92 @@ class DemoWindow : public Rml::EventListener 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 -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 +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 window_1 = Rml::MakeUnique("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 window_2 = Rml::MakeUnique("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; diff --git a/Samples/basic/treeview/src/FileBrowser.cpp b/Samples/basic/treeview/src/FileBrowser.cpp index 336aaddcb..441f863ee 100644 --- a/Samples/basic/treeview/src/FileBrowser.cpp +++ b/Samples/basic/treeview/src/FileBrowser.cpp @@ -30,6 +30,7 @@ #include #include #include +#include namespace FileBrowser { @@ -48,7 +49,7 @@ static Rml::Vector 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)); diff --git a/Samples/basic/treeview/src/main.cpp b/Samples/basic/treeview/src/main.cpp index 57b60e56f..f0a9a52d9 100644 --- a/Samples/basic/treeview/src/main.cpp +++ b/Samples/basic/treeview/src/main.cpp @@ -26,87 +26,56 @@ * */ +#include "FileBrowser.h" #include #include -#include +#include +#include #include -#include -#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 -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 +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; diff --git a/Samples/invaders/src/EventManager.cpp b/Samples/invaders/src/EventManager.cpp index c7bda1904..4f35dd008 100644 --- a/Samples/invaders/src/EventManager.cpp +++ b/Samples/invaders/src/EventManager.cpp @@ -27,12 +27,13 @@ */ #include "EventManager.h" +#include "EventHandler.h" +#include "GameDetails.h" #include #include #include +#include #include -#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") { diff --git a/Samples/invaders/src/main.cpp b/Samples/invaders/src/main.cpp index 6aae5a95d..be71182ed 100644 --- a/Samples/invaders/src/main.cpp +++ b/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 -#include -#include -#include -#include #include "DecoratorInstancerDefender.h" #include "DecoratorInstancerStarfield.h" #include "ElementGame.h" @@ -40,83 +35,59 @@ #include "EventInstancer.h" #include "EventManager.h" #include "HighScores.h" +#include +#include +#include +#include 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 -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 +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 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; } diff --git a/Samples/luainvaders/src/LuaInterface.cpp b/Samples/luainvaders/src/LuaInterface.cpp index c527dcffb..0f1e4d02e 100644 --- a/Samples/luainvaders/src/LuaInterface.cpp +++ b/Samples/luainvaders/src/LuaInterface.cpp @@ -1,14 +1,15 @@ #include "LuaInterface.h" -#include -#include +#include "ElementGameInstancer.h" #include "Game.h" #include "GameDetails.h" -#include -#include -#include #include "HighScores.h" +#include +#include #include -#include "ElementGameInstancer.h" +#include +#include +#include +#include //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; } diff --git a/Samples/luainvaders/src/main.cpp b/Samples/luainvaders/src/main.cpp index 30bdb369a..e771dee6a 100644 --- a/Samples/luainvaders/src/main.cpp +++ b/Samples/luainvaders/src/main.cpp @@ -26,87 +26,65 @@ * */ -#include -#include -#include - -#include -#include -#include #include "DecoratorInstancerDefender.h" #include "DecoratorInstancerStarfield.h" #include "ElementGame.h" #include "HighScores.h" #include "LuaInterface.h" +#include +#include +#include +#include +#include Rml::Context* context = nullptr; -void DoAllocConsole(); - -ShellRenderInterfaceExtensions *shell_renderer; - -void GameLoop() -{ - context->Update(); - - shell_renderer->PrepareRenderBuffer(); - context->Render(); - shell_renderer->PresentRenderBuffer(); -} - #if defined RMLUI_PLATFORM_WIN32 -#include -int APIENTRY WinMain(HINSTANCE, HINSTANCE, char*, int) + #include +int APIENTRY WinMain(HINSTANCE /*instance_handle*/, HINSTANCE /*previous_instance_handle*/, char* /*command_line*/, int /*command_show*/) #else -int main(int, char**) +int main(int /*argc*/, char** /*argv*/) #endif { - -#ifdef RMLUI_PLATFORM_WIN32 - DoAllocConsole(); -#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("RmlUi Invaders from Mars (Lua Powered)", 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 (Lua Powered)", 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(); // Initialise the Lua interface Rml::Lua::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) { 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 decorator instancers. DecoratorInstancerStarfield decorator_starfield; @@ -121,7 +99,17 @@ int main(int, char**) LuaInterface::Initialise(Rml::Lua::Interpreter::GetLuaState()); //the tables/functions defined in the samples Rml::Lua::Interpreter::LoadFile(Rml::String("luainvaders/lua/start.lua")); - Shell::EventLoop(GameLoop); + bool running = true; + while (running) + { + running = Backend::ProcessEvents(context, &Shell::ProcessKeyDownShortcuts); + + context->Update(); + + Backend::BeginFrame(); + context->Render(); + Backend::PresentFrame(); + } // Shut down the game singletons. HighScores::Shutdown(); @@ -129,58 +117,8 @@ int main(int, char**) // Shutdown RmlUi. Rml::Shutdown(); - Shell::CloseWindow(); + Backend::Shutdown(); Shell::Shutdown(); return 0; } - -#ifdef RMLUI_PLATFORM_WIN32 - -#include -#include -#include -#include - -void DoAllocConsole() -{ - static const WORD MAX_CONSOLE_LINES = 500; - int hConHandle; - HANDLE lStdHandle; - CONSOLE_SCREEN_BUFFER_INFO coninfo; - FILE *fp; - - // allocate a console for this app - AllocConsole(); - - // set the screen buffer to be big enough to let us scroll text - GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &coninfo); - coninfo.dwSize.Y = MAX_CONSOLE_LINES; - SetConsoleScreenBufferSize(GetStdHandle(STD_OUTPUT_HANDLE), coninfo.dwSize); - - // redirect unbuffered STDOUT to the console - lStdHandle = GetStdHandle(STD_OUTPUT_HANDLE); - hConHandle = _open_osfhandle((intptr_t)lStdHandle, _O_TEXT); - fp = _fdopen( hConHandle, "w" ); - - *stdout = *fp; - setvbuf( stdout, nullptr, _IONBF, 0 ); - - // redirect unbuffered STDIN to the console - lStdHandle = GetStdHandle(STD_INPUT_HANDLE); - hConHandle = _open_osfhandle((intptr_t)lStdHandle, _O_TEXT); - fp = _fdopen( hConHandle, "r" ); - - *stdin = *fp; - setvbuf( stdin, nullptr, _IONBF, 0 ); - - // redirect unbuffered STDERR to the console - lStdHandle = GetStdHandle(STD_ERROR_HANDLE); - hConHandle = _open_osfhandle((intptr_t)lStdHandle, _O_TEXT); - fp = _fdopen( hConHandle, "w" ); - *stderr = *fp; - - setvbuf( stderr, nullptr, _IONBF, 0 ); - ShowWindow(GetConsoleWindow(), SW_SHOW); -} -#endif diff --git a/Samples/readme.md b/Samples/readme.md index a0752d4c7..16b764b28 100644 --- a/Samples/readme.md +++ b/Samples/readme.md @@ -21,9 +21,6 @@ This directory contains basic applications that demonstrate initialisation, usag - `drag` dragging elements between containers - `loaddocument` loading your first document - `lottie` playing Lottie animations, only enabled with the [Lottie plugin](https://mikke89.github.io/RmlUiDoc/pages/cpp_manual/lottie.html) -- `sdl2` integrating with SDL2 using an OpenGL-renderer -- `sdl2_sdlrenderer` integrating with SDL2 using a native SDL-renderer -- `sfml2` integrating with SFML2 - `svg` render SVG images, only enabled with the [SVG plugin](https://mikke89.github.io/RmlUiDoc/pages/cpp_manual/svg.html) - `transform` demonstration of transforms - `treeview` using data bindings to create a file browser @@ -38,7 +35,7 @@ Lua version of the invaders sample. Only installed with the Lua plugin. #### `shell` -Common platform specific code used by all the samples for open windows, processing input and access files. Supports Windows, macOS and Linux. +The shell is mainly a wrapper around the [backends](../Backends/), used by all the samples to initialize the interfaces and open windows for rendering on the selected backend. #### `tutorial` diff --git a/Samples/shell/include/Input.h b/Samples/shell/include/Input.h deleted file mode 100644 index e9a6d980c..000000000 --- a/Samples/shell/include/Input.h +++ /dev/null @@ -1,51 +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 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_SHELL_INPUT_H -#define RMLUI_SHELL_INPUT_H - -#include -#include - -class Input -{ -public: - /// Sets the context to send input events to. - /// @param[in] context The context to send input events to. - static void SetContext(Rml::Context* context); - /// Returns the character code for a key identifer / key modifier combination. - /// @param[in] key_identifier The key to generate a character code for. - /// @param[in] key_modifier_state The configuration of the key modifiers. - /// @return The character code. - static Rml::Character GetCharacterCode(Rml::Input::KeyIdentifier key_identifier, int key_modifier_state); - -protected: - static Rml::Context* context; -}; - -#endif diff --git a/Samples/shell/src/precompiled.h b/Samples/shell/include/PlatformExtensions.h similarity index 77% rename from Samples/shell/src/precompiled.h rename to Samples/shell/include/PlatformExtensions.h index 06c7151a7..be0f96782 100644 --- a/Samples/shell/src/precompiled.h +++ b/Samples/shell/include/PlatformExtensions.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,11 +26,18 @@ * */ -#ifndef RMLUISHELLPRECOMPILED_H -#define RMLUISHELLPRECOMPILED_H +#ifndef RMLUI_SHELL_PLATFORMEXTENSIONS_H +#define RMLUI_SHELL_PLATFORMEXTENSIONS_H + +#include + +namespace PlatformExtensions { + +Rml::String FindSamplesRoot(); + +Rml::StringList ListDirectories(const Rml::String& in_directory); +Rml::StringList ListFiles(const Rml::String& in_directory, const Rml::String& extension = Rml::String()); -#include -#include -#include +} // namespace PlatformExtensions #endif diff --git a/Samples/shell/include/win32/IncludeWindows.h b/Samples/shell/include/RendererExtensions.h similarity index 79% rename from Samples/shell/include/win32/IncludeWindows.h rename to Samples/shell/include/RendererExtensions.h index 6934cee9f..2e1fe2824 100644 --- a/Samples/shell/include/win32/IncludeWindows.h +++ b/Samples/shell/include/RendererExtensions.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,22 +26,22 @@ * */ -#ifndef RMLUI_SHELL_WIN32_INCLUDEWINDOWS_H -#define RMLUI_SHELL_WIN32_INCLUDEWINDOWS_H +#ifndef RMLUI_SHELL_RENDEREREXTENSIONS_H +#define RMLUI_SHELL_RENDEREREXTENSIONS_H -#if !defined _WIN32_WINNT || _WIN32_WINNT < 0x0601 - #undef _WIN32_WINNT - // Target Windows 7 - #define _WIN32_WINNT 0x0601 -#endif +#include -#define UNICODE -#define _UNICODE -#define WIN32_LEAN_AND_MEAN -#ifndef NOMINMAX -#define NOMINMAX -#endif +namespace RendererExtensions { + +// Extensions used by the test suite +struct Image { + int width = 0; + int height = 0; + int num_components = 0; + Rml::UniquePtr data; +}; +Image CaptureScreen(); -#include +} // namespace RendererExtensions #endif diff --git a/Samples/shell/include/Shell.h b/Samples/shell/include/Shell.h index cab55a858..e358e7083 100644 --- a/Samples/shell/include/Shell.h +++ b/Samples/shell/include/Shell.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,77 +26,30 @@ * */ -#ifndef RMLUI_SHELL_H -#define RMLUI_SHELL_H +#ifndef RMLUI_SHELL_SHELL_H +#define RMLUI_SHELL_SHELL_H -#include #include -#include -#include "ShellRenderInterfaceExtensions.h" +#include +#include /** - Shell functions for creating windows, attaching OpenGL and handling input in a platform independent way. - @author Lloyd Weehuizen + Provides common functionality required for the built-in RmlUi samples. */ +namespace Shell { -class Shell -{ -public: - /// Initialise the shell. - static bool Initialise(); - /// Shutdown the shell. - static void Shutdown(); - - /// Finds the Samples root directory. - static Rml::String FindSamplesRoot(); - - /// Loads the default fonts from the given path. - static void LoadFonts(const char* directory); - - /// List files in the given directory. An initial forward slash '/' makes it relative to the samples root. - static Rml::StringList ListFiles(const Rml::String& in_directory, const Rml::String& extension = Rml::String()); - /// List subdirectories in the given directory. An initial forward slash '/' makes it relative to the samples root. - static Rml::StringList ListDirectories(const Rml::String& in_directory); - - /// Open a platform specific window, optionally initialising an OpenGL context on it. - /// @param[in] title Title of the window. - /// @param[in] srie Provides the interface for attaching a renderer to the window and performing related bits of interface. - static bool OpenWindow(const char* title, ShellRenderInterfaceExtensions *_shell_renderer, unsigned int width, unsigned int height, bool allow_resize); - /// Close the active window. - static void CloseWindow(); - - /// Returns a platform-dependent handle to the window. - static void* GetWindowHandle(); - - /// Run the event loop, calling the idle function every frame. - using ShellIdleFunction = void(*)(); - static void EventLoop(ShellIdleFunction idle_function); - static void RequestExit(); - - /// Display an error message. - static void DisplayError(const char* fmt, ...); - /// Log a message to the debugger. - static void Log(const char* fmt, ...); - - /// Get the number of seconds that have passed since shell startup. - static double GetElapsedTime(); - - /// Set mouse cursor. - static void SetMouseCursor(const Rml::String& cursor_name); - - /// Set clipboard text. - static void SetClipboardText(const Rml::String& text); +// Initializes and sets a custom file interface used for locating the included RmlUi asset files. +bool Initialize(); +// Destroys all resources constructed by the shell. +void Shutdown(); - /// Get clipboard text. - static void GetClipboardText(Rml::String& text); - - /// Sets the RmlUi context to send window resized events to. - static void SetContext(Rml::Context* context); +// Loads the fonts included with the RmlUi samples. +void LoadFonts(); - /// Return the dp-ratio of the system. - static float GetDensityIndependentPixelRatio(); -}; +// Process key down events to handle shortcuts common to all samples. +// @return True if the event is still propagating, false if it was handled here. +bool ProcessKeyDownShortcuts(Rml::Context* context, Rml::Input::KeyIdentifier key, int key_modifier, float native_dp_ratio, bool priority); -#include "ShellSystemInterface.h" +} // namespace Shell #endif diff --git a/Samples/shell/include/ShellRenderInterfaceExtensions.h b/Samples/shell/include/ShellRenderInterfaceExtensions.h deleted file mode 100644 index 6d5690bba..000000000 --- a/Samples/shell/include/ShellRenderInterfaceExtensions.h +++ /dev/null @@ -1,62 +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) 2014, David Wimsey - * 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_SHELL_SHELLRENDERINTERFACEEXTENSIONS_H -#define RMLUI_SHELL_SHELLRENDERINTERFACEEXTENSIONS_H - -/** - Extensions to the RenderInterface class used by the Samples Shell to - handle various bits of rendering and rendering upkeep that would normally - be handled by the application rather than the RmlUi RenderInterface class. - @author David Wimsey - */ - -class ShellRenderInterfaceExtensions -{ -public: - /** - * @param[in] width width of viewport - * @param[in] height height of viewport - */ - virtual void SetViewport(int width, int height) = 0; - - /// Attach the internal window buffer to a native window - /// @param[in] nativeWindow A handle to the OS specific native window handle - virtual bool AttachToNative(void *nativeWindow) = 0; - - /// Detach and cleanup the internal window buffer from a native window - virtual void DetachFromNative(void) = 0; - - /// Prepares the render buffer for drawing, in OpenGL, this would call glClear(); - virtual void PrepareRenderBuffer(void) = 0; - - /// Presents the rendered framebuffer to the screen, in OpenGL this would cal glSwapBuffers(); - virtual void PresentRenderBuffer(void) = 0; -}; - -#endif diff --git a/Samples/shell/include/ShellRenderInterfaceOpenGL.h b/Samples/shell/include/ShellRenderInterfaceOpenGL.h deleted file mode 100644 index 42694e85c..000000000 --- a/Samples/shell/include/ShellRenderInterfaceOpenGL.h +++ /dev/null @@ -1,106 +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 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_SHELL_SHELLRENDERINTERFACEOPENGL_H -#define RMLUI_SHELL_SHELLRENDERINTERFACEOPENGL_H - -#include -#include "ShellOpenGL.h" - -/** - Low level OpenGL render interface for RmlUi - @author Peter Curry - */ - -class ShellRenderInterfaceOpenGL : public Rml::RenderInterface, public ShellRenderInterfaceExtensions -{ -public: - ShellRenderInterfaceOpenGL(); - - /// 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 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; - - /// Called by RmlUi when it wants to render application-compiled geometry. - 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; - - /// Called by RmlUi when it wants to set the current transform matrix to a new matrix. - void SetTransform(const Rml::Matrix4f* transform) override; - - // Extensions used by the test suite - struct Image { - int width = 0; - int height = 0; - int num_components = 0; - Rml::UniquePtr data; - }; - Image CaptureScreen(); - - // ShellRenderInterfaceExtensions - void SetViewport(int width, int height) override; - bool AttachToNative(void *nativeWindow) override; - void DetachFromNative(void) override; - void PrepareRenderBuffer(void) override; - void PresentRenderBuffer(void) override; - -protected: - int m_width; - int m_height; - bool m_transform_enabled; - -#if defined(RMLUI_PLATFORM_MACOSX) - AGLContext gl_context; -#elif defined(RMLUI_PLATFORM_LINUX) - struct __X11NativeWindowData nwData; - GLXContext gl_context; -#elif defined(RMLUI_PLATFORM_WIN32) - HWND window_handle; - HDC device_context; - HGLRC render_context; -#else -#error Platform is undefined, this must be resolved so gl_context is usable. -#endif -}; - -#endif diff --git a/Samples/shell/include/win32/InputWin32.h b/Samples/shell/include/win32/InputWin32.h deleted file mode 100644 index d69ca8bca..000000000 --- a/Samples/shell/include/win32/InputWin32.h +++ /dev/null @@ -1,55 +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 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_SHELL_INPUTWIN32_H -#define RMLUI_SHELL_INPUTWIN32_H - -#include -#include -#include - -/** - Processes Windows input events and passes them through to RmlUi. Feel free to take this class and integrate it - with your project. - @author Lloyd Weehuizen - */ - -class InputWin32 : public Input -{ -public: - static bool Initialise(); - static void Shutdown(); - - /// Process the Windows message. - static void ProcessWindowsEvent(HWND window, UINT message, WPARAM w_param, LPARAM l_param); -}; - -Rml::String ConvertToUTF8(const std::wstring& wstr); -std::wstring ConvertToUTF16(const Rml::String& str); - -#endif diff --git a/Samples/shell/include/x11/InputX11.h b/Samples/shell/include/x11/InputX11.h deleted file mode 100644 index a44b86080..000000000 --- a/Samples/shell/include/x11/InputX11.h +++ /dev/null @@ -1,60 +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 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_SHELL_X11_INPUTX11_H -#define RMLUI_SHELL_X11_INPUTX11_H - -#include -#include - -#include "Input.h" - -/** - * Input Wrapper Code - * - * Feel free to take this class and integrate it with your project. - * - * @author Lloyd Weehuizen - */ - -class InputX11 : public Input -{ -public: - static bool Initialise(); - static void Shutdown(); - - /// Process the windows message - static void ProcessXEvent(Display* display, const XEvent& event); - - // Initialises Xkb extension if available or reads keymap from X11 - // server otherwise. This is internal to the X11 subsystem and - // has nothing to do with RmlUi's mapping. - static void InitialiseX11Keymap(Display *display); -}; - -#endif diff --git a/Samples/shell/src/Input.cpp b/Samples/shell/src/Input.cpp deleted file mode 100644 index 6054b3140..000000000 --- a/Samples/shell/src/Input.cpp +++ /dev/null @@ -1,357 +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 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 - -/** - This map contains 4 different mappings from key identifiers to character codes. Each entry represents a different - combination of shift and capslock state. - */ - -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 - } -}; - -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, - '/', - '=' - } -}; - - - -Rml::Context* Input::context = nullptr; - - - -// Sets the context to send input events to. -void Input::SetContext(Rml::Context* _context) -{ - context = _context; -} - - - -// Returns the character code for a key identifer / key modifier combination. -Rml::Character Input::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; -} diff --git a/Samples/shell/src/PlatformExtensions.cpp b/Samples/shell/src/PlatformExtensions.cpp new file mode 100644 index 000000000..8e9e3ba32 --- /dev/null +++ b/Samples/shell/src/PlatformExtensions.cpp @@ -0,0 +1,243 @@ +/* + * 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 "../include/PlatformExtensions.h" +#include + +#if defined RMLUI_PLATFORM_WIN32 + + #include + #include + #include + +#elif defined RMLUI_PLATFORM_MACOSX + + #include + #include + #include + +#elif defined RMLUI_PLATFORM_UNIX + + #include + #include + #include + #include + #include + +#endif + +Rml::String PlatformExtensions::FindSamplesRoot() +{ +#ifdef RMLUI_PLATFORM_WIN32 + + const char* candidate_paths[] = {"", "..\\Samples\\", "..\\..\\Samples\\", "..\\..\\..\\Samples\\", "..\\..\\..\\..\\Samples\\"}; + + // Fetch the path of the executable, test the candidate paths appended to that. + char executable_file_name[MAX_PATH]; + if (GetModuleFileNameA(NULL, executable_file_name, MAX_PATH) >= MAX_PATH && GetLastError() == ERROR_INSUFFICIENT_BUFFER) + { + executable_file_name[0] = 0; + } + + Rml::String executable_path(executable_file_name); + executable_path = executable_path.substr(0, executable_path.rfind('\\') + 1); + + // We assume we have found the correct path if we can find the lookup file from it + const char* lookup_file = "assets\\rml.rcss"; + + for (const char* relative_path : candidate_paths) + { + Rml::String absolute_path = executable_path + relative_path; + + if (PathFileExistsA(Rml::String(absolute_path + lookup_file).c_str())) + { + char canonical_path[MAX_PATH]; + if (!PathCanonicalizeA(canonical_path, absolute_path.c_str())) + canonical_path[0] = 0; + + return Rml::String(canonical_path); + } + } + + return Rml::String(); + +#elif defined RMLUI_PLATFORM_MACOSX + + Rml::String path = "../../Samples/"; + + // Find the location of the executable. + CFBundleRef bundle = CFBundleGetMainBundle(); + CFURLRef executable_url = CFBundleCopyExecutableURL(bundle); + CFStringRef executable_posix_file_name = CFURLCopyFileSystemPath(executable_url, kCFURLPOSIXPathStyle); + CFIndex max_length = CFStringGetMaximumSizeOfFileSystemRepresentation(executable_posix_file_name); + char* executable_file_name = new char[max_length]; + if (!CFStringGetFileSystemRepresentation(executable_posix_file_name, executable_file_name, max_length)) + executable_file_name[0] = 0; + + Rml::String executable_path = Rml::String(executable_file_name); + executable_path = executable_path.substr(0, executable_path.rfind("/") + 1); + + delete[] executable_file_name; + CFRelease(executable_posix_file_name); + CFRelease(executable_url); + + return executable_path + "../../../" + path; + +#elif defined RMLUI_PLATFORM_UNIX + + char executable_file_name[PATH_MAX]; + ssize_t len = readlink("/proc/self/exe", executable_file_name, PATH_MAX); + if (len == -1) + { + printf("Unable to determine the executable path!\n"); + executable_file_name[0] = 0; + } + else + { + // readlink() does not append a null byte to buf. + executable_file_name[len] = 0; + } + Rml::String executable_path = Rml::String(executable_file_name); + executable_path = executable_path.substr(0, executable_path.rfind("/") + 1); + + // We assume we have found the correct path if we can find the lookup file from it. + const char* lookup_file = "assets/rml.rcss"; + + // For "../Samples/" to be valid we must be in the Build directory. + // If "../" is valid we are probably in the installation directory. + // Some build setups may nest the executables deeper in a build directory, try them last. + const char* candidate_paths[] = {"", "../", "../Samples/", "../../Samples/", "../../../Samples/", "../../../../Samples/"}; + + auto isRegularFile = [](const Rml::String& path) -> bool { + struct stat sb; + return stat(path.c_str(), &sb) == 0 && S_ISREG(sb.st_mode); + }; + + for (const char* relative_path : candidate_paths) + { + Rml::String absolute_path = executable_path + relative_path; + Rml::String absolute_lookup_file = absolute_path + lookup_file; + + if (isRegularFile(absolute_lookup_file)) + { + return absolute_path; + } + } + + printf("Unable to find the path to the samples root!\n"); + + return Rml::String(); + +#else + + return Rml::String(); + +#endif +} + +enum class ListType { Files, Directories }; + +static Rml::StringList ListFilesOrDirectories(ListType type, const Rml::String& directory, const Rml::String& extension) +{ + if (directory.empty()) + return Rml::StringList(); + + Rml::StringList result; + +#ifdef RMLUI_PLATFORM_WIN32 + + const Rml::String find_path = directory + "/*." + (extension.empty() ? Rml::String("*") : extension); + + _finddata_t find_data; + intptr_t find_handle = _findfirst(find_path.c_str(), &find_data); + if (find_handle != -1) + { + do + { + if (strcmp(find_data.name, ".") == 0 || strcmp(find_data.name, "..") == 0) + continue; + + bool is_directory = ((find_data.attrib & _A_SUBDIR) == _A_SUBDIR); + bool is_file = (!is_directory && ((find_data.attrib & _A_NORMAL) == _A_NORMAL)); + + if (((type == ListType::Files) && is_file) || ((type == ListType::Directories) && is_directory)) + { + result.push_back(find_data.name); + } + + } while (_findnext(find_handle, &find_data) == 0); + + _findclose(find_handle); + } + +#else + + struct dirent** file_list = nullptr; + const int file_count = scandir(directory.c_str(), &file_list, 0, alphasort); + if (file_count == -1) + return Rml::StringList(); + + for (int i = 0; i < file_count; i++) + { + if (strcmp(file_list[i]->d_name, ".") == 0 || strcmp(file_list[i]->d_name, "..") == 0) + continue; + + bool is_directory = ((file_list[i]->d_type & DT_DIR) == DT_DIR); + bool is_file = ((file_list[i]->d_type & DT_REG) == DT_REG); + + if (!extension.empty()) + { + const char* last_dot = strrchr(file_list[i]->d_name, '.'); + if (!last_dot || strcmp(last_dot + 1, extension.c_str()) != 0) + continue; + } + + if ((type == ListType::Files && is_file) || (type == ListType::Directories && is_directory)) + { + result.push_back(file_list[i]->d_name); + } + } + for (int i = 0; i < file_count; i++) + free(file_list[i]); + + free(file_list); + +#endif + + return result; +} + +Rml::StringList PlatformExtensions::ListDirectories(const Rml::String& in_directory) +{ + return ListFilesOrDirectories(ListType::Directories, in_directory, Rml::String()); +} + +Rml::StringList PlatformExtensions::ListFiles(const Rml::String& in_directory, const Rml::String& extension) +{ + return ListFilesOrDirectories(ListType::Files, in_directory, extension); +} diff --git a/Samples/shell/include/ShellOpenGL.h b/Samples/shell/src/RendererExtensions.cpp similarity index 50% rename from Samples/shell/include/ShellOpenGL.h rename to Samples/shell/src/RendererExtensions.cpp index aee51cc22..18eb2bfe8 100644 --- a/Samples/shell/include/ShellOpenGL.h +++ b/Samples/shell/src/RendererExtensions.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,34 +26,67 @@ * */ -#ifndef RMLUI_SHELL_SHELLOPENGL_H -#define RMLUI_SHELL_SHELLOPENGL_H - +#include "../include/RendererExtensions.h" +#include #include -#if defined RMLUI_PLATFORM_WIN32 -#include "win32/IncludeWindows.h" -#include -#include -#elif defined RMLUI_PLATFORM_MACOSX -#include -#include -#include -#include -#elif defined RMLUI_PLATFORM_UNIX -#include -#include -#include -#include - -#include - -struct __X11NativeWindowData -{ - Window window; - Display *display; - XVisualInfo *visual_info; -}; +#if defined RMLUI_RENDERER_GL2 + + #if defined RMLUI_PLATFORM_WIN32 + #include + #include + #include + #elif defined RMLUI_PLATFORM_MACOSX + #include + #include + #include + #include + #elif defined RMLUI_PLATFORM_UNIX + #include + #include + #include + #include + #include + #endif + #endif +RendererExtensions::Image RendererExtensions::CaptureScreen() +{ +#if defined RMLUI_RENDERER_GL2 + + int viewport[4] = {}; // x, y, width, height + glGetIntegerv(GL_VIEWPORT, viewport); + + Image image; + image.num_components = 3; + image.width = viewport[2]; + image.height = viewport[3]; + + if (image.width < 1 || image.height < 1) + return Image(); + + const int byte_size = image.width * image.height * image.num_components; + image.data = Rml::UniquePtr(new Rml::byte[byte_size]); + + glReadPixels(0, 0, image.width, image.height, GL_RGB, GL_UNSIGNED_BYTE, image.data.get()); + + bool result = true; + GLenum err; + while ((err = glGetError()) != GL_NO_ERROR) + { + result = false; + Rml::Log::Message(Rml::Log::LT_ERROR, "Could not capture screenshot, got GL error: 0x%x", err); + } + + if (!result) + return Image(); + + return image; + +#else + + return Image(); + #endif +} diff --git a/Samples/shell/src/Shell.cpp b/Samples/shell/src/Shell.cpp index 13bb5dd5d..02765f6ce 100644 --- a/Samples/shell/src/Shell.cpp +++ b/Samples/shell/src/Shell.cpp @@ -26,116 +26,120 @@ * */ -#include "Shell.h" +#include "../include/Shell.h" +#include "../include/PlatformExtensions.h" +#include "../include/ShellFileInterface.h" +#include #include -#include +#include +#include +#include -#ifdef RMLUI_PLATFORM_WIN32 -#include -#else -#include -#endif +static Rml::UniquePtr file_interface; -/// Loads the default fonts from the given path. -void Shell::LoadFonts(const char* directory) +bool Shell::Initialize() { + // Find the path to the 'Samples' directory. + Rml::String root = PlatformExtensions::FindSamplesRoot(); + if (root.empty()) + return false; + + // The shell overrides the default file interface so that absolute paths in RML/RCSS-documents are relative to the 'Samples' directory. + file_interface = Rml::MakeUnique(root); + Rml::SetFileInterface(file_interface.get()); + + return true; +} + +void Shell::Shutdown() +{ + file_interface.reset(); +} + +void Shell::LoadFonts() +{ + const Rml::String directory = "assets/"; + struct FontFace { - Rml::String filename; + const char* 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 }, + {"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(Rml::String(directory) + face.filename, face.fallback_face); - } + Rml::LoadFontFace(directory + face.filename, face.fallback_face); } - -enum class ListType { Files, Directories }; - -static Rml::StringList ListFilesOrDirectories(ListType type, const Rml::String& directory, const Rml::String& extension) +bool Shell::ProcessKeyDownShortcuts(Rml::Context* context, Rml::Input::KeyIdentifier key, int key_modifier, float native_dp_ratio, bool priority) { - if (directory.empty()) - return Rml::StringList(); - - Rml::StringList result; + if (!context) + return true; -#ifdef RMLUI_PLATFORM_WIN32 - const Rml::String find_path = directory + "/*." + (extension.empty() ? Rml::String("*") : extension); + // Result should return true to allow the event to propagate to the next handler. + bool result = false; - _finddata_t find_data; - intptr_t find_handle = _findfirst(find_path.c_str(), &find_data); - if (find_handle != -1) + // This function is intended to be called twice by the backend, before and after submitting the key event to the context. This way we can + // intercept shortcuts that should take priority over the context, and then handle any shortcuts of lower priority if the context did not + // intercept it. + if (priority) { - do - { - if (strcmp(find_data.name, ".") == 0 || - strcmp(find_data.name, "..") == 0) - continue; + // Priority shortcuts are handled before submitting the key to the context. - bool is_directory = ((find_data.attrib & _A_SUBDIR) == _A_SUBDIR); - bool is_file = (!is_directory && ((find_data.attrib & _A_NORMAL) == _A_NORMAL)); - - if (((type == ListType::Files) && is_file) || - ((type == ListType::Directories) && is_directory)) - { - result.push_back(find_data.name); - } - - } while (_findnext(find_handle, &find_data) == 0); - - _findclose(find_handle); + // Toggle debugger and set dp-ratio using Ctrl +/-/0 keys. + if (key == Rml::Input::KI_F8) + { + Rml::Debugger::SetVisible(!Rml::Debugger::IsVisible()); + } + else if (key == Rml::Input::KI_0 && key_modifier & Rml::Input::KM_CTRL) + { + context->SetDensityIndependentPixelRatio(native_dp_ratio); + } + else if (key == Rml::Input::KI_1 && key_modifier & Rml::Input::KM_CTRL) + { + context->SetDensityIndependentPixelRatio(1.f); + } + else if ((key == Rml::Input::KI_OEM_MINUS || key == Rml::Input::KI_SUBTRACT) && key_modifier & Rml::Input::KM_CTRL) + { + const float new_dp_ratio = Rml::Math::Max(context->GetDensityIndependentPixelRatio() / 1.2f, 0.5f); + context->SetDensityIndependentPixelRatio(new_dp_ratio); + } + else if ((key == Rml::Input::KI_OEM_PLUS || key == Rml::Input::KI_ADD) && key_modifier & Rml::Input::KM_CTRL) + { + const float new_dp_ratio = Rml::Math::Min(context->GetDensityIndependentPixelRatio() * 1.2f, 2.5f); + context->SetDensityIndependentPixelRatio(new_dp_ratio); + } + else + { + // Propagate the key down event to the context. + result = true; + } } -#else - struct dirent** file_list = nullptr; - const int file_count = scandir(directory.c_str(), &file_list, 0, alphasort); - if (file_count == -1) - return Rml::StringList(); - - for (int i = 0; i < file_count; i++) + else { - if (strcmp(file_list[i]->d_name, ".") == 0 || - strcmp(file_list[i]->d_name, "..") == 0) - continue; - - bool is_directory = ((file_list[i]->d_type & DT_DIR) == DT_DIR); - bool is_file = ((file_list[i]->d_type & DT_REG) == DT_REG); - - if (!extension.empty()) + // We arrive here when no priority keys are detected and the key was not consumed by the context. Check for shortcuts of lower priority. + if (key == Rml::Input::KI_R && key_modifier & Rml::Input::KM_CTRL) { - const char* last_dot = strrchr(file_list[i]->d_name, '.'); - if (!last_dot || strcmp(last_dot + 1, extension.c_str()) != 0) - continue; + for (int i = 0; i < context->GetNumDocuments(); i++) + { + Rml::ElementDocument* document = context->GetDocument(i); + const Rml::String& src = document->GetSourceURL(); + if (src.size() > 4 && src.substr(src.size() - 4) == ".rml") + { + document->ReloadStyleSheet(); + } + } } - - if ((type == ListType::Files && is_file) || - (type == ListType::Directories && is_directory)) + else { - result.push_back(file_list[i]->d_name); + result = true; } } - for (int i = 0; i < file_count; i++) - free(file_list[i]); - free(file_list); -#endif return result; } - -Rml::StringList Shell::ListDirectories(const Rml::String& in_directory) -{ - return ListFilesOrDirectories(ListType::Directories, in_directory, Rml::String()); -} - -Rml::StringList Shell::ListFiles(const Rml::String& in_directory, const Rml::String& extension) -{ - return ListFilesOrDirectories(ListType::Files, in_directory, extension); -} - diff --git a/Samples/shell/src/ShellFileInterface.cpp b/Samples/shell/src/ShellFileInterface.cpp index 080c1e2c7..d97826d52 100644 --- a/Samples/shell/src/ShellFileInterface.cpp +++ b/Samples/shell/src/ShellFileInterface.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,16 +26,12 @@ * */ -#include +#include "../include/ShellFileInterface.h" #include -ShellFileInterface::ShellFileInterface(const Rml::String& root) : root(root) -{ -} +ShellFileInterface::ShellFileInterface(const Rml::String& root) : root(root) {} -ShellFileInterface::~ShellFileInterface() -{ -} +ShellFileInterface::~ShellFileInterface() {} // Opens a file. Rml::FileHandle ShellFileInterface::Open(const Rml::String& path) @@ -43,33 +39,33 @@ Rml::FileHandle ShellFileInterface::Open(const Rml::String& path) // Attempt to open the file relative to the application's root. FILE* fp = fopen((root + path).c_str(), "rb"); if (fp != nullptr) - return (Rml::FileHandle) fp; + return (Rml::FileHandle)fp; // Attempt to open the file relative to the current working directory. fp = fopen(path.c_str(), "rb"); - return (Rml::FileHandle) fp; + return (Rml::FileHandle)fp; } // Closes a previously opened file. void ShellFileInterface::Close(Rml::FileHandle file) { - fclose((FILE*) file); + fclose((FILE*)file); } // Reads data from a previously opened file. size_t ShellFileInterface::Read(void* buffer, size_t size, Rml::FileHandle file) { - return fread(buffer, 1, size, (FILE*) file); + return fread(buffer, 1, size, (FILE*)file); } // Seeks to a point in a previously opened file. bool ShellFileInterface::Seek(Rml::FileHandle file, long offset, int origin) { - return fseek((FILE*) file, offset, origin) == 0; + return fseek((FILE*)file, offset, origin) == 0; } // Returns the current position of the file pointer. size_t ShellFileInterface::Tell(Rml::FileHandle file) { - return ftell((FILE*) file); + return ftell((FILE*)file); } diff --git a/Samples/shell/src/ShellRenderInterfaceOpenGL.cpp b/Samples/shell/src/ShellRenderInterfaceOpenGL.cpp deleted file mode 100644 index 624fcfe76..000000000 --- a/Samples/shell/src/ShellRenderInterfaceOpenGL.cpp +++ /dev/null @@ -1,327 +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 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 -#include -#include -#include -#include -#include - -#define GL_CLAMP_TO_EDGE 0x812F - -ShellRenderInterfaceOpenGL::ShellRenderInterfaceOpenGL() : m_width(0), m_height(0), m_transform_enabled(false) -{ - -} - -// Called by RmlUi when it wants to render geometry that it does not wish to optimise. -void ShellRenderInterfaceOpenGL::RenderGeometry(Rml::Vertex* vertices, int RMLUI_UNUSED_PARAMETER(num_vertices), int* indices, int num_indices, const Rml::TextureHandle texture, const Rml::Vector2f& translation) -{ - RMLUI_UNUSED(num_vertices); - - glPushMatrix(); - glTranslatef(translation.x, translation.y, 0); - - glVertexPointer(2, GL_FLOAT, sizeof(Rml::Vertex), &vertices[0].position); - glEnableClientState(GL_COLOR_ARRAY); - 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); - 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(); -} - -// Called by RmlUi when it wants to compile geometry it believes will be static for the forseeable future. -Rml::CompiledGeometryHandle ShellRenderInterfaceOpenGL::CompileGeometry(Rml::Vertex* RMLUI_UNUSED_PARAMETER(vertices), int RMLUI_UNUSED_PARAMETER(num_vertices), int* RMLUI_UNUSED_PARAMETER(indices), int RMLUI_UNUSED_PARAMETER(num_indices), const Rml::TextureHandle RMLUI_UNUSED_PARAMETER(texture)) -{ - RMLUI_UNUSED(vertices); - RMLUI_UNUSED(num_vertices); - RMLUI_UNUSED(indices); - RMLUI_UNUSED(num_indices); - RMLUI_UNUSED(texture); - - return (Rml::CompiledGeometryHandle) nullptr; -} - -// Called by RmlUi when it wants to render application-compiled geometry. -void ShellRenderInterfaceOpenGL::RenderCompiledGeometry(Rml::CompiledGeometryHandle RMLUI_UNUSED_PARAMETER(geometry), const Rml::Vector2f& RMLUI_UNUSED_PARAMETER(translation)) -{ - RMLUI_UNUSED(geometry); - RMLUI_UNUSED(translation); -} - -// Called by RmlUi when it wants to release application-compiled geometry. -void ShellRenderInterfaceOpenGL::ReleaseCompiledGeometry(Rml::CompiledGeometryHandle RMLUI_UNUSED_PARAMETER(geometry)) -{ - RMLUI_UNUSED(geometry); -} - -// Called by RmlUi when it wants to enable or disable scissoring to clip content. -void ShellRenderInterfaceOpenGL::EnableScissorRegion(bool enable) -{ - if (enable) { - if (!m_transform_enabled) { - glEnable(GL_SCISSOR_TEST); - glDisable(GL_STENCIL_TEST); - } else { - glDisable(GL_SCISSOR_TEST); - glEnable(GL_STENCIL_TEST); - } - } else { - glDisable(GL_SCISSOR_TEST); - glDisable(GL_STENCIL_TEST); - } -} - -// Called by RmlUi when it wants to change the scissor region. -void ShellRenderInterfaceOpenGL::SetScissorRegion(int x, int y, int width, int height) -{ - if (!m_transform_enabled) { - glScissor(x, m_height - (y + height), width, height); - } else { - // clear the stencil buffer - glStencilMask(GLuint(-1)); - glClear(GL_STENCIL_BUFFER_BIT); - - // fill the stencil buffer - glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); - glDepthMask(GL_FALSE); - glStencilFunc(GL_NEVER, 1, GLuint(-1)); - glStencilOp(GL_REPLACE, GL_KEEP, GL_KEEP); - - float fx = (float)x; - float fy = (float)y; - float fwidth = (float)width; - float fheight = (float)height; - - // draw transformed quad - GLfloat vertices[] = { - fx, fy, 0, - fx, fy + fheight, 0, - fx + fwidth, fy + fheight, 0, - fx + fwidth, fy, 0 - }; - glDisableClientState(GL_COLOR_ARRAY); - glVertexPointer(3, GL_FLOAT, 0, vertices); - GLushort indices[] = { 1, 2, 0, 3 }; - glDrawElements(GL_TRIANGLE_STRIP, 4, GL_UNSIGNED_SHORT, indices); - glEnableClientState(GL_COLOR_ARRAY); - - // prepare for drawing the real thing - glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); - glDepthMask(GL_TRUE); - glStencilMask(0); - glStencilFunc(GL_EQUAL, 1, GLuint(-1)); - } -} - -// 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() - -// Called by RmlUi when a texture is required by the library. -bool ShellRenderInterfaceOpenGL::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); - - RMLUI_ASSERTMSG(buffer_size > sizeof(TGAHeader), "Texture file size is smaller than TGAHeader, file must be corrupt or otherwise invalid"); - if(buffer_size <= sizeof(TGAHeader)) - { - 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."); - 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"); - 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; -} - -// Called by RmlUi when a texture is required to be built from an internally-generated sequence of pixels. -bool ShellRenderInterfaceOpenGL::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) - { - printf("Failed to generate textures\n"); - 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; -} - -// Called by RmlUi when a loaded texture is no longer required. -void ShellRenderInterfaceOpenGL::ReleaseTexture(Rml::TextureHandle texture_handle) -{ - glDeleteTextures(1, (GLuint*) &texture_handle); -} - -// Called by RmlUi when it wants to set the current transform matrix to a new matrix. -void ShellRenderInterfaceOpenGL::SetTransform(const Rml::Matrix4f* transform) -{ - m_transform_enabled = (bool)transform; - - if (transform) - { - if (std::is_same::value) - glLoadMatrixf(transform->data()); - else if (std::is_same::value) - glLoadMatrixf(transform->Transpose().data()); - } - else - glLoadIdentity(); -} - - -ShellRenderInterfaceOpenGL::Image ShellRenderInterfaceOpenGL::CaptureScreen() -{ - Image image; - image.num_components = 3; - image.width = m_width; - image.height = m_height; - - const int byte_size = image.width * image.height * image.num_components; - image.data = Rml::UniquePtr(new Rml::byte[byte_size]); - - glReadPixels(0, 0, image.width, image.height, GL_RGB, GL_UNSIGNED_BYTE, image.data.get()); - - bool result = true; - GLenum err; - while ((err = glGetError()) != GL_NO_ERROR) - { - result = false; - Rml::Log::Message(Rml::Log::LT_ERROR, "Could not capture screenshot, got GL error: 0x%x", err); - } - - if (!result) - return Image(); - - return image; -} diff --git a/Samples/shell/src/ShellSystemInterface.cpp b/Samples/shell/src/ShellSystemInterface.cpp deleted file mode 100644 index 9cd2cfe3d..000000000 --- a/Samples/shell/src/ShellSystemInterface.cpp +++ /dev/null @@ -1,51 +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 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 -#include - -// Get the number of seconds elapsed since the start of the application -double ShellSystemInterface::GetElapsedTime() -{ - return Shell::GetElapsedTime(); -} - -void ShellSystemInterface::SetMouseCursor(const Rml::String& cursor_name) -{ - Shell::SetMouseCursor(cursor_name); -} - -void ShellSystemInterface::SetClipboardText(const Rml::String& text) -{ - Shell::SetClipboardText(text); -} - -void ShellSystemInterface::GetClipboardText(Rml::String& text) -{ - Shell::GetClipboardText(text); -} diff --git a/Samples/shell/src/macosx/InputMacOSX.cpp b/Samples/shell/src/macosx/InputMacOSX.cpp deleted file mode 100644 index 824990cec..000000000 --- a/Samples/shell/src/macosx/InputMacOSX.cpp +++ /dev/null @@ -1,302 +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 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 -#include -#include -#include -#include -#include -#include - -// Defines for Carbon key modifiers. -#define KEY_ALT 256 -#define KEY_SHIFT 512 -#define KEY_CAPS 1024 -#define KEY_OPTION 2048 -#define KEY_CTRL 4096 - -static void InitialiseKeymap(); -static int GetKeyModifierState(EventRef event); - -static const int KEYMAP_SIZE = 256; -static Rml::Input::KeyIdentifier key_identifier_map[KEYMAP_SIZE]; - -bool InputMacOSX::Initialise() -{ - InitialiseKeymap(); - return true; -} - -void InputMacOSX::Shutdown() -{ -} - -OSStatus InputMacOSX::EventHandler(EventHandlerCallRef next_handler, EventRef event, void* p) -{ - // Process all mouse and keyboard events - switch (GetEventClass(event)) - { - case kEventClassMouse: - { - switch (GetEventKind(event)) - { - case kEventMouseDown: - { - EventMouseButton mouse_button; - if (GetEventParameter(event, kEventParamMouseButton, typeMouseButton, nullptr, sizeof(EventMouseButton), nullptr, &mouse_button) == noErr) - context->ProcessMouseButtonDown(mouse_button - 1, GetKeyModifierState(event)); - } - break; - - case kEventMouseUp: - { - EventMouseButton mouse_button; - if (GetEventParameter(event, kEventParamMouseButton, typeMouseButton, nullptr, sizeof(EventMouseButton), nullptr, &mouse_button) == noErr) - context->ProcessMouseButtonUp(mouse_button - 1, GetKeyModifierState(event)); - } - break; - - case kEventMouseWheelMoved: - { - EventMouseWheelAxis axis; - SInt32 delta; - - if (GetEventParameter(event, kEventParamMouseWheelAxis, typeMouseWheelAxis, nullptr, sizeof(EventMouseWheelAxis), nullptr, &axis) == noErr && - GetEventParameter(event, kEventParamMouseWheelDelta, typeLongInteger, nullptr, sizeof(SInt32), nullptr, &delta) == noErr) - { - if (axis == kEventMouseWheelAxisY) - context->ProcessMouseWheel(-delta, GetKeyModifierState(event)); - } - } - break; - - case kEventMouseMoved: - case kEventMouseDragged: - { - HIPoint position; - if (GetEventParameter(event, kEventParamWindowMouseLocation, typeHIPoint, nullptr, sizeof(HIPoint), nullptr, &position) == noErr) - context->ProcessMouseMove(position.x, position.y - 22, GetKeyModifierState(event)); - } - break; - } - } - break; - - case kEventClassKeyboard: - { - switch (GetEventKind(event)) - { - case kEventRawKeyDown: - { - UInt32 key_code; - if (GetEventParameter(event, kEventParamKeyCode, typeUInt32, nullptr, sizeof(UInt32), nullptr, &key_code) == noErr) - { - Rml::Input::KeyIdentifier key_identifier = key_identifier_map[key_code & 0xFF]; - int key_modifier_state = GetKeyModifierState(event); - - // Check for F8 to toggle the debugger. - if (key_identifier == Rml::Input::KI_F8) - { - Rml::Debugger::SetVisible(!Rml::Debugger::IsVisible()); - break; - } - - bool propagates = false; - - 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)) - context->ProcessTextInput(character); - - // Check for low-priority key combinations that are only activated if not already consumed by the context. - if (propagates && key_identifier == Rml::Input::KI_R && key_modifier_state & Rml::Input::KM_CTRL) - { - for (int i = 0; i < context->GetNumDocuments(); i++) - { - Rml::ElementDocument* document = context->GetDocument(i); - const Rml::String& src = document->GetSourceURL(); - if (src.size() > 4 && src.substr(src.size() - 4) == ".rml") - { - document->ReloadStyleSheet(); - } - } - } - } - } - break; - - case kEventRawKeyUp: - { - UInt32 key_code; - if (GetEventParameter(event, kEventParamKeyCode, typeUInt32, nullptr, sizeof(UInt32), nullptr, &key_code) == noErr) - { - Rml::Input::KeyIdentifier key_identifier = key_identifier_map[key_code & 0xFF]; - int key_modifier_state = GetKeyModifierState(event); - - if (key_identifier != Rml::Input::KI_UNKNOWN) - context->ProcessKeyUp(key_identifier, key_modifier_state); - } - } - break; - } - } - break; - } - - return CallNextEventHandler(next_handler, event); -} - -static int GetKeyModifierState(EventRef event) -{ - int key_modifier_state = 0; - - UInt32 carbon_key_modifier_state; - if (GetEventParameter(event, kEventParamKeyModifiers, typeUInt32, nullptr, sizeof(UInt32), nullptr, &carbon_key_modifier_state) == noErr) - { - if (carbon_key_modifier_state & KEY_ALT) - key_modifier_state |= Rml::Input::KM_ALT; - if (carbon_key_modifier_state & KEY_SHIFT) - key_modifier_state |= Rml::Input::KM_SHIFT; - if (carbon_key_modifier_state & KEY_CAPS) - key_modifier_state |= Rml::Input::KM_CAPSLOCK; - if (carbon_key_modifier_state & KEY_OPTION) - key_modifier_state |= Rml::Input::KM_META; - if (carbon_key_modifier_state & KEY_CTRL) - key_modifier_state |= Rml::Input::KM_CTRL; - } - - return key_modifier_state; -} - -static void InitialiseKeymap() -{ - // Initialise the key map with default values. - memset(key_identifier_map, sizeof(key_identifier_map), 0); - - key_identifier_map[0x00] = Rml::Input::KI_A; - key_identifier_map[0x01] = Rml::Input::KI_S; - key_identifier_map[0x02] = Rml::Input::KI_D; - key_identifier_map[0x03] = Rml::Input::KI_F; - key_identifier_map[0x04] = Rml::Input::KI_H; - key_identifier_map[0x05] = Rml::Input::KI_G; - key_identifier_map[0x06] = Rml::Input::KI_Z; - key_identifier_map[0x07] = Rml::Input::KI_X; - key_identifier_map[0x08] = Rml::Input::KI_C; - key_identifier_map[0x09] = Rml::Input::KI_V; - key_identifier_map[0x0B] = Rml::Input::KI_B; - key_identifier_map[0x0C] = Rml::Input::KI_Q; - key_identifier_map[0x0D] = Rml::Input::KI_W; - key_identifier_map[0x0E] = Rml::Input::KI_E; - key_identifier_map[0x0F] = Rml::Input::KI_R; - key_identifier_map[0x10] = Rml::Input::KI_Y; - key_identifier_map[0x11] = Rml::Input::KI_T; - key_identifier_map[0x12] = Rml::Input::KI_1; - key_identifier_map[0x13] = Rml::Input::KI_2; - key_identifier_map[0x14] = Rml::Input::KI_3; - key_identifier_map[0x15] = Rml::Input::KI_4; - key_identifier_map[0x16] = Rml::Input::KI_6; - key_identifier_map[0x17] = Rml::Input::KI_5; - key_identifier_map[0x18] = Rml::Input::KI_OEM_PLUS; - key_identifier_map[0x19] = Rml::Input::KI_9; - key_identifier_map[0x1A] = Rml::Input::KI_7; - key_identifier_map[0x1B] = Rml::Input::KI_OEM_MINUS; - key_identifier_map[0x1C] = Rml::Input::KI_8; - key_identifier_map[0x1D] = Rml::Input::KI_0; - key_identifier_map[0x1E] = Rml::Input::KI_OEM_6; - key_identifier_map[0x1F] = Rml::Input::KI_O; - key_identifier_map[0x20] = Rml::Input::KI_U; - key_identifier_map[0x21] = Rml::Input::KI_OEM_4; - key_identifier_map[0x22] = Rml::Input::KI_I; - key_identifier_map[0x23] = Rml::Input::KI_P; - key_identifier_map[0x24] = Rml::Input::KI_RETURN; - key_identifier_map[0x25] = Rml::Input::KI_L; - key_identifier_map[0x26] = Rml::Input::KI_J; - key_identifier_map[0x27] = Rml::Input::KI_OEM_7; - key_identifier_map[0x28] = Rml::Input::KI_K; - key_identifier_map[0x29] = Rml::Input::KI_OEM_1; - key_identifier_map[0x2A] = Rml::Input::KI_OEM_5; - key_identifier_map[0x2B] = Rml::Input::KI_OEM_COMMA; - key_identifier_map[0x2C] = Rml::Input::KI_OEM_2; - key_identifier_map[0x2D] = Rml::Input::KI_N; - key_identifier_map[0x2E] = Rml::Input::KI_M; - key_identifier_map[0x2F] = Rml::Input::KI_OEM_PERIOD; - key_identifier_map[0x30] = Rml::Input::KI_TAB; - key_identifier_map[0x31] = Rml::Input::KI_SPACE; - key_identifier_map[0x32] = Rml::Input::KI_OEM_3; - key_identifier_map[0x33] = Rml::Input::KI_BACK; - key_identifier_map[0x35] = Rml::Input::KI_ESCAPE; - key_identifier_map[0x37] = Rml::Input::KI_LMETA; - key_identifier_map[0x38] = Rml::Input::KI_LSHIFT; - key_identifier_map[0x39] = Rml::Input::KI_CAPITAL; - key_identifier_map[0x3A] = Rml::Input::KI_LMENU; - key_identifier_map[0x3B] = Rml::Input::KI_LCONTROL; - key_identifier_map[0x41] = Rml::Input::KI_DECIMAL; - key_identifier_map[0x43] = Rml::Input::KI_MULTIPLY; - key_identifier_map[0x45] = Rml::Input::KI_ADD; - key_identifier_map[0x4B] = Rml::Input::KI_DIVIDE; - key_identifier_map[0x4C] = Rml::Input::KI_NUMPADENTER; - key_identifier_map[0x4E] = Rml::Input::KI_SUBTRACT; - key_identifier_map[0x51] = Rml::Input::KI_OEM_PLUS; - key_identifier_map[0x52] = Rml::Input::KI_NUMPAD0; - key_identifier_map[0x53] = Rml::Input::KI_NUMPAD1; - key_identifier_map[0x54] = Rml::Input::KI_NUMPAD2; - key_identifier_map[0x55] = Rml::Input::KI_NUMPAD3; - key_identifier_map[0x56] = Rml::Input::KI_NUMPAD4; - key_identifier_map[0x57] = Rml::Input::KI_NUMPAD5; - key_identifier_map[0x58] = Rml::Input::KI_NUMPAD6; - key_identifier_map[0x59] = Rml::Input::KI_NUMPAD7; - key_identifier_map[0x5B] = Rml::Input::KI_NUMPAD8; - key_identifier_map[0x5C] = Rml::Input::KI_NUMPAD9; - key_identifier_map[0x60] = Rml::Input::KI_F5; - key_identifier_map[0x61] = Rml::Input::KI_F6; - key_identifier_map[0x62] = Rml::Input::KI_F7; - key_identifier_map[0x63] = Rml::Input::KI_F3; - key_identifier_map[0x64] = Rml::Input::KI_F8; - key_identifier_map[0x65] = Rml::Input::KI_F9; - key_identifier_map[0x67] = Rml::Input::KI_F11; - key_identifier_map[0x69] = Rml::Input::KI_F13; - key_identifier_map[0x6B] = Rml::Input::KI_F14; - key_identifier_map[0x6D] = Rml::Input::KI_F10; - key_identifier_map[0x6F] = Rml::Input::KI_F12; - key_identifier_map[0x71] = Rml::Input::KI_F15; - key_identifier_map[0x73] = Rml::Input::KI_HOME; - key_identifier_map[0x74] = Rml::Input::KI_PRIOR; - key_identifier_map[0x75] = Rml::Input::KI_DELETE; - key_identifier_map[0x76] = Rml::Input::KI_F4; - key_identifier_map[0x77] = Rml::Input::KI_END; - key_identifier_map[0x78] = Rml::Input::KI_F2; - key_identifier_map[0x79] = Rml::Input::KI_NEXT; - key_identifier_map[0x7A] = Rml::Input::KI_F1; - key_identifier_map[0x7B] = Rml::Input::KI_LEFT; - key_identifier_map[0x7C] = Rml::Input::KI_RIGHT; - key_identifier_map[0x7D] = Rml::Input::KI_DOWN; - key_identifier_map[0x7E] = Rml::Input::KI_UP; -} diff --git a/Samples/shell/src/macosx/ShellMacOSX.cpp b/Samples/shell/src/macosx/ShellMacOSX.cpp deleted file mode 100644 index a574f21d4..000000000 --- a/Samples/shell/src/macosx/ShellMacOSX.cpp +++ /dev/null @@ -1,334 +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 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 "Shell.h" -#include -#include "ShellFileInterface.h" -#include "macosx/InputMacOSX.h" -#include -#include -#include -#include -#include - -static const EventTypeSpec INPUT_EVENTS[] = { - { kEventClassKeyboard, kEventRawKeyDown }, - { kEventClassKeyboard, kEventRawKeyUp }, - { kEventClassKeyboard, kEventRawKeyModifiersChanged }, - - { kEventClassMouse, kEventMouseDown }, - { kEventClassMouse, kEventMouseUp }, - { kEventClassMouse, kEventMouseMoved }, - { kEventClassMouse, kEventMouseDragged }, - { kEventClassMouse, kEventMouseWheelMoved }, -}; - -static const EventTypeSpec WINDOW_EVENTS[] = { - { kEventClassWindow, kEventWindowClose }, - { kEventClassWindow, kEventWindowBoundsChanged }, -}; - -static Rml::Context* context = nullptr; -static ShellRenderInterfaceExtensions* shell_renderer; -static UniquePtr file_interface; - -static WindowRef window; -static timeval start_time; -static Rml::String clipboard_text; -static int window_width = 0; -static int window_height = 0; - -static void IdleTimerCallback(EventLoopTimerRef timer, EventLoopIdleTimerMessage inState, void* p); -static OSStatus EventHandler(EventHandlerCallRef next_handler, EventRef event, void* p); - -static void UpdateWindowDimensions(int width = 0, int height = 0) -{ - if (width > 0) - window_width = width; - if (height > 0) - window_height = height; - if (context) - context->SetDimensions(Rml::Vector2i(window_width, window_height)); - if (shell_renderer) - shell_renderer->SetViewport(window_width, window_height); -} - -bool Shell::Initialise() -{ - gettimeofday(&start_time, nullptr); - - InputMacOSX::Initialise(); - - Rml::String root = FindSamplesRoot(); - - file_interface = Rml::MakeUnique(root); - Rml::SetFileInterface(file_interface.get()); - - return true; -} - -void Shell::Shutdown() -{ - file_interface.reset(); -} - -Rml::String Shell::FindSamplesRoot() -{ - Rml::String path = "../../Samples/"; - - // Find the location of the executable. - CFBundleRef bundle = CFBundleGetMainBundle(); - CFURLRef executable_url = CFBundleCopyExecutableURL(bundle); - CFStringRef executable_posix_file_name = CFURLCopyFileSystemPath(executable_url, kCFURLPOSIXPathStyle); - CFIndex max_length = CFStringGetMaximumSizeOfFileSystemRepresentation(executable_posix_file_name); - char* executable_file_name = new char[max_length]; - if (!CFStringGetFileSystemRepresentation(executable_posix_file_name, executable_file_name, max_length)) - executable_file_name[0] = 0; - - Rml::String executable_path = Rml::String(executable_file_name); - executable_path = executable_path.substr(0, executable_path.rfind("/") + 1); - - delete[] executable_file_name; - CFRelease(executable_posix_file_name); - CFRelease(executable_url); - - return (executable_path + "../../../" + path); -} - -bool Shell::OpenWindow(const char* name, ShellRenderInterfaceExtensions *_shell_renderer, unsigned int width, unsigned int height, bool allow_resize) -{ - shell_renderer = _shell_renderer; - Rect content_bounds = { 60, 20, 60 + height, 20 + width }; - window_width = width; - window_height = height; - - OSStatus result = CreateNewWindow(kDocumentWindowClass, - (allow_resize ? (kWindowStandardDocumentAttributes | kWindowLiveResizeAttribute) : - kWindowCloseBoxAttribute) | kWindowStandardHandlerAttribute, - &content_bounds, - &window); - if (result != noErr) - return false; - - CFStringRef window_title = CFStringCreateWithCString(nullptr, name, kCFStringEncodingUTF8); - if (result != noErr) - return false; - - result = SetWindowTitleWithCFString(window, window_title); - if (result != noErr) - { - CFRelease(window_title); - return false; - } - - CFRelease(window_title); - - ShowWindow(window); - - if(shell_renderer != nullptr) { - shell_renderer->AttachToNative(window); - } - return true; -} - -void Shell::CloseWindow() -{ - if(shell_renderer) { - shell_renderer->DetachFromNative(); - } - - // Close the window. - HideWindow(window); - ReleaseWindow(window); -} - -void Shell::EventLoop(ShellIdleFunction idle_function) -{ - OSStatus error; - error = InstallApplicationEventHandler(NewEventHandlerUPP(InputMacOSX::EventHandler), - GetEventTypeCount(INPUT_EVENTS), - INPUT_EVENTS, - nullptr, - nullptr); - if (error != noErr) - DisplayError("Unable to install handler for input events, error: %d.", error); - - error = InstallWindowEventHandler(window, - NewEventHandlerUPP(EventHandler), - GetEventTypeCount(WINDOW_EVENTS), - WINDOW_EVENTS, - nullptr, - nullptr); - if (error != noErr) - DisplayError("Unable to install handler for window events, error: %d.", error); - - EventLoopTimerRef timer; - error = InstallEventLoopIdleTimer(GetMainEventLoop(), // inEventLoop - 0, // inFireDelay - 5 * kEventDurationMillisecond, // inInterval (200 Hz) - NewEventLoopIdleTimerUPP(IdleTimerCallback), // inTimerProc - (void*) idle_function, // inTimerData, - &timer // outTimer - ); - if (error != noErr) - DisplayError("Unable to install Carbon event loop timer, error: %d.", error); - - RunApplicationEventLoop(); -} - -void Shell::RequestExit() -{ - EventRef event; - OSStatus result = CreateEvent(nullptr, // default allocator - kEventClassApplication, - kEventAppQuit, - 0, - kEventAttributeNone, - &event); - - if (result == noErr) - PostEventToQueue(GetMainEventQueue(), event, kEventPriorityStandard); -} - -void Shell::DisplayError(const char* fmt, ...) -{ - const int buffer_size = 1024; - char buffer[buffer_size]; - va_list argument_list; - - // Print the message to the buffer. - va_start(argument_list, fmt); - int len = vsnprintf(buffer, buffer_size - 2, fmt, argument_list); - if (len < 0 || len > buffer_size - 2) - { - len = buffer_size - 2; - } - buffer[len] = '\n'; - buffer[len + 1] = '\0'; - va_end(argument_list); - - fprintf(stderr, "%s", buffer); -} - -void Shell::Log(const char* fmt, ...) -{ - const int buffer_size = 1024; - char buffer[buffer_size]; - va_list argument_list; - - // Print the message to the buffer. - va_start(argument_list, fmt); - int len = vsnprintf(buffer, buffer_size - 2, fmt, argument_list); - if ( len < 0 || len > buffer_size - 2 ) - { - len = buffer_size - 2; - } - buffer[len] = '\n'; - buffer[len + 1] = '\0'; - va_end(argument_list); - - printf("%s", buffer); -} - -double Shell::GetElapsedTime() -{ - struct timeval now; - - gettimeofday(&now, nullptr); - - double sec = now.tv_sec - start_time.tv_sec; - double usec = now.tv_usec; - double result = sec + (usec / 1000000.0); - - return result; -} - -void Shell::SetMouseCursor(const Rml::String& cursor_name) -{ - // Not implemented -} - -void Shell::SetClipboardText(const Rml::String& text) -{ - // Todo: interface with system clipboard - clipboard_text = text; -} - -void Shell::GetClipboardText(Rml::String& text) -{ - // Todo: interface with system clipboard - text = clipboard_text; -} - -void Shell::SetContext(Rml::Context* new_context) -{ - context = new_context; - UpdateWindowDimensions(); -} - -static void IdleTimerCallback(EventLoopTimerRef timer, EventLoopIdleTimerMessage inState, void* p) -{ - Shell::ShellIdleFunction function = (Shell::ShellIdleFunction) p; - function(); -} - -static OSStatus EventHandler(EventHandlerCallRef next_handler, EventRef event, void* p) -{ - switch (GetEventClass(event)) - { - case kEventClassWindow: - { - switch (GetEventKind(event)) - { - case kEventWindowClose: - Shell::RequestExit(); - break; - case kEventWindowBoundsChanged: - // Window resized, update the rmlui context - UInt32 attributes; - GetEventParameter(event, kEventParamAttributes, typeUInt32, nullptr, sizeof(UInt32), nullptr, &attributes); - - if(attributes & kWindowBoundsChangeSizeChanged) - { - Rect bounds; - GetEventParameter(event, kEventParamCurrentBounds, typeQDRectangle, nullptr, sizeof(Rect), nullptr, &bounds); - - UInt32 width = bounds.right - bounds.left; - UInt32 height = bounds.bottom - bounds.top; - - UpdateWindowDimensions((int)width, (int)height); - } - break; - } - } - break; - } - -// InputMacOSX::ProcessCarbonEvent(event); - return CallNextEventHandler(next_handler, event); -} diff --git a/Samples/shell/src/macosx/ShellRenderInterfaceExtensionsOpenGL_MacOSX.cpp b/Samples/shell/src/macosx/ShellRenderInterfaceExtensionsOpenGL_MacOSX.cpp deleted file mode 100644 index 516053953..000000000 --- a/Samples/shell/src/macosx/ShellRenderInterfaceExtensionsOpenGL_MacOSX.cpp +++ /dev/null @@ -1,121 +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 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 -#include -#include -#include -#include - -void ShellRenderInterfaceOpenGL::SetViewport(int width, int height) -{ - if(m_width != width || m_height != height) { - Rml::Matrix4f projection, view; - - m_width = width; - m_height = height; - - glViewport(0, 0, width, height); - projection = Rml::Matrix4f::ProjectOrtho(0, (float)width, (float)height, 0, -10000, 10000); - glMatrixMode(GL_PROJECTION); - glLoadMatrixf(projection); - view = Rml::Matrix4f::Identity(); - glMatrixMode(GL_MODELVIEW); - glLoadMatrixf(view); - - aglUpdateContext(gl_context); - } -} - -bool ShellRenderInterfaceOpenGL::AttachToNative(void *nativeWindow) -{ - WindowRef window = (WindowRef)nativeWindow; - static GLint attributes[] = - { - AGL_RGBA, - AGL_DOUBLEBUFFER, - AGL_ALPHA_SIZE, 8, - AGL_DEPTH_SIZE, 24, - AGL_STENCIL_SIZE, 8, - AGL_ACCELERATED, - AGL_NONE - }; - - AGLPixelFormat pixel_format = aglChoosePixelFormat(nullptr, 0, attributes); - if (pixel_format == nullptr) - return false; - - CGrafPtr window_port = GetWindowPort(window); - if (window_port == nullptr) - return false; - - this->gl_context = aglCreateContext(pixel_format, nullptr); - if (this->gl_context == nullptr) - return false; - - aglSetDrawable(this->gl_context, window_port); - aglSetCurrentContext(this->gl_context); - - aglDestroyPixelFormat(pixel_format); - - // Set up the GL state. - glClearColor(0, 0, 0, 1); - glEnableClientState(GL_VERTEX_ARRAY); - glEnableClientState(GL_COLOR_ARRAY); - - glEnable(GL_BLEND); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - - glMatrixMode(GL_PROJECTION); - glLoadIdentity(); - Rect crect; - GetWindowBounds(window, kWindowContentRgn, &crect); - glOrtho(0, (crect.right - crect.left), (crect.bottom - crect.top), 0, -1, 1); - - glMatrixMode(GL_MODELVIEW); - glLoadIdentity(); -} - -void ShellRenderInterfaceOpenGL::DetachFromNative() -{ - // Shutdown OpenGL if necessary. - aglSetCurrentContext(nullptr); - aglSetDrawable(this->gl_context, nullptr); - aglDestroyContext(this->gl_context); -} - -void ShellRenderInterfaceOpenGL::PrepareRenderBuffer() -{ - glClear(GL_COLOR_BUFFER_BIT); -} - -void ShellRenderInterfaceOpenGL::PresentRenderBuffer() -{ - // Flips the OpenGL buffers. - aglSwapBuffers(this->gl_context); -} diff --git a/Samples/shell/src/win32/InputWin32.cpp b/Samples/shell/src/win32/InputWin32.cpp deleted file mode 100644 index db0553070..000000000 --- a/Samples/shell/src/win32/InputWin32.cpp +++ /dev/null @@ -1,453 +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 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 -#include -#include -#include -#include -#include -#include -#include -#include - -static int GetKeyModifierState(); -static void InitialiseKeymap(); - -static const int KEYMAP_SIZE = 256; -static Rml::Input::KeyIdentifier key_identifier_map[KEYMAP_SIZE]; - -bool InputWin32::Initialise() -{ - InitialiseKeymap(); - return true; -} - -void InputWin32::Shutdown() -{ -} - -void InputWin32::ProcessWindowsEvent(HWND window, UINT message, WPARAM w_param, LPARAM l_param) -{ - if (context == nullptr) - return; - - // Process all mouse and keyboard events - switch (message) - { - case WM_LBUTTONDOWN: - context->ProcessMouseButtonDown(0, GetKeyModifierState()); - SetCapture(window); - break; - - case WM_LBUTTONUP: - ReleaseCapture(); - context->ProcessMouseButtonUp(0, GetKeyModifierState()); - break; - - case WM_RBUTTONDOWN: - context->ProcessMouseButtonDown(1, GetKeyModifierState()); - break; - - case WM_RBUTTONUP: - context->ProcessMouseButtonUp(1, GetKeyModifierState()); - break; - - case WM_MBUTTONDOWN: - context->ProcessMouseButtonDown(2, GetKeyModifierState()); - break; - - case WM_MBUTTONUP: - context->ProcessMouseButtonUp(2, GetKeyModifierState()); - break; - - case WM_MOUSEMOVE: - context->ProcessMouseMove(static_cast((short)LOWORD(l_param)), static_cast((short)HIWORD(l_param)), GetKeyModifierState()); - break; - - case WM_MOUSEWHEEL: - context->ProcessMouseWheel(static_cast((short) HIWORD(w_param)) / static_cast(-WHEEL_DELTA), GetKeyModifierState()); - break; - - case WM_KEYDOWN: - { - Rml::Input::KeyIdentifier key_identifier = key_identifier_map[w_param]; - const int key_modifier_state = GetKeyModifierState(); - - // Toggle debugger and set 'dp'-ratio ctrl +/-/0 keys. These global shortcuts take priority. - if (key_identifier == Rml::Input::KI_F8) - { - Rml::Debugger::SetVisible(!Rml::Debugger::IsVisible()); - } - else if (key_identifier == Rml::Input::KI_0 && key_modifier_state & Rml::Input::KM_CTRL) - { - context->SetDensityIndependentPixelRatio(Shell::GetDensityIndependentPixelRatio()); - } - else if (key_identifier == Rml::Input::KI_1 && key_modifier_state & Rml::Input::KM_CTRL) - { - context->SetDensityIndependentPixelRatio(1.f); - } - else if (key_identifier == Rml::Input::KI_OEM_MINUS && key_modifier_state & Rml::Input::KM_CTRL) - { - const float new_dp_ratio = Rml::Math::Max(context->GetDensityIndependentPixelRatio() / 1.2f, 0.5f); - context->SetDensityIndependentPixelRatio(new_dp_ratio); - } - else if (key_identifier == Rml::Input::KI_OEM_PLUS && key_modifier_state & Rml::Input::KM_CTRL) - { - const float new_dp_ratio = Rml::Math::Min(context->GetDensityIndependentPixelRatio() * 1.2f, 2.5f); - context->SetDensityIndependentPixelRatio(new_dp_ratio); - } - else - { - // No global shortcuts detected, submit the key to the context. - if (context->ProcessKeyDown(key_identifier, key_modifier_state)) - { - // The key was not consumed, check for shortcuts that are of lower priority. - if (key_identifier == Rml::Input::KI_R && key_modifier_state & Rml::Input::KM_CTRL) - { - for (int i = 0; i < context->GetNumDocuments(); i++) - { - Rml::ElementDocument* document = context->GetDocument(i); - const Rml::String& src = document->GetSourceURL(); - if (src.size() > 4 && src.substr(src.size() - 4) == ".rml") - { - document->ReloadStyleSheet(); - } - } - - } - } - } - } - 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) - context->ProcessTextInput(character); - } - } - break; - - case WM_KEYUP: - context->ProcessKeyUp(key_identifier_map[w_param], GetKeyModifierState()); - break; - } -} - -static int GetKeyModifierState() -{ - int key_modifier_state = 0; - - // Query the state of all modifier keys - if (GetKeyState(VK_CAPITAL) & 1) - { - key_modifier_state |= Rml::Input::KM_CAPSLOCK; - } - - if (HIWORD(GetKeyState(VK_SHIFT)) & 1) - { - key_modifier_state |= Rml::Input::KM_SHIFT; - } - - if (GetKeyState(VK_NUMLOCK) & 1) - { - key_modifier_state |= Rml::Input::KM_NUMLOCK; - } - - 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__) - -static void InitialiseKeymap() -{ - // Initialise the key map with default values. - memset(key_identifier_map, 0, sizeof(key_identifier_map)); - - // Assign individual values. - key_identifier_map['A'] = Rml::Input::KI_A; - key_identifier_map['B'] = Rml::Input::KI_B; - key_identifier_map['C'] = Rml::Input::KI_C; - key_identifier_map['D'] = Rml::Input::KI_D; - key_identifier_map['E'] = Rml::Input::KI_E; - key_identifier_map['F'] = Rml::Input::KI_F; - key_identifier_map['G'] = Rml::Input::KI_G; - key_identifier_map['H'] = Rml::Input::KI_H; - key_identifier_map['I'] = Rml::Input::KI_I; - key_identifier_map['J'] = Rml::Input::KI_J; - key_identifier_map['K'] = Rml::Input::KI_K; - key_identifier_map['L'] = Rml::Input::KI_L; - key_identifier_map['M'] = Rml::Input::KI_M; - key_identifier_map['N'] = Rml::Input::KI_N; - key_identifier_map['O'] = Rml::Input::KI_O; - key_identifier_map['P'] = Rml::Input::KI_P; - key_identifier_map['Q'] = Rml::Input::KI_Q; - key_identifier_map['R'] = Rml::Input::KI_R; - key_identifier_map['S'] = Rml::Input::KI_S; - key_identifier_map['T'] = Rml::Input::KI_T; - key_identifier_map['U'] = Rml::Input::KI_U; - key_identifier_map['V'] = Rml::Input::KI_V; - key_identifier_map['W'] = Rml::Input::KI_W; - key_identifier_map['X'] = Rml::Input::KI_X; - key_identifier_map['Y'] = Rml::Input::KI_Y; - key_identifier_map['Z'] = Rml::Input::KI_Z; - - key_identifier_map['0'] = Rml::Input::KI_0; - key_identifier_map['1'] = Rml::Input::KI_1; - key_identifier_map['2'] = Rml::Input::KI_2; - key_identifier_map['3'] = Rml::Input::KI_3; - key_identifier_map['4'] = Rml::Input::KI_4; - key_identifier_map['5'] = Rml::Input::KI_5; - key_identifier_map['6'] = Rml::Input::KI_6; - key_identifier_map['7'] = Rml::Input::KI_7; - key_identifier_map['8'] = Rml::Input::KI_8; - key_identifier_map['9'] = Rml::Input::KI_9; - - key_identifier_map[VK_BACK] = Rml::Input::KI_BACK; - key_identifier_map[VK_TAB] = Rml::Input::KI_TAB; - - key_identifier_map[VK_CLEAR] = Rml::Input::KI_CLEAR; - key_identifier_map[VK_RETURN] = Rml::Input::KI_RETURN; - - key_identifier_map[VK_PAUSE] = Rml::Input::KI_PAUSE; - key_identifier_map[VK_CAPITAL] = Rml::Input::KI_CAPITAL; - - key_identifier_map[VK_KANA] = Rml::Input::KI_KANA; - key_identifier_map[VK_HANGUL] = Rml::Input::KI_HANGUL; - key_identifier_map[VK_JUNJA] = Rml::Input::KI_JUNJA; - key_identifier_map[VK_FINAL] = Rml::Input::KI_FINAL; - key_identifier_map[VK_HANJA] = Rml::Input::KI_HANJA; - key_identifier_map[VK_KANJI] = Rml::Input::KI_KANJI; - - key_identifier_map[VK_ESCAPE] = Rml::Input::KI_ESCAPE; - - key_identifier_map[VK_CONVERT] = Rml::Input::KI_CONVERT; - key_identifier_map[VK_NONCONVERT] = Rml::Input::KI_NONCONVERT; - key_identifier_map[VK_ACCEPT] = Rml::Input::KI_ACCEPT; - key_identifier_map[VK_MODECHANGE] = Rml::Input::KI_MODECHANGE; - - key_identifier_map[VK_SPACE] = Rml::Input::KI_SPACE; - key_identifier_map[VK_PRIOR] = Rml::Input::KI_PRIOR; - key_identifier_map[VK_NEXT] = Rml::Input::KI_NEXT; - key_identifier_map[VK_END] = Rml::Input::KI_END; - key_identifier_map[VK_HOME] = Rml::Input::KI_HOME; - key_identifier_map[VK_LEFT] = Rml::Input::KI_LEFT; - key_identifier_map[VK_UP] = Rml::Input::KI_UP; - key_identifier_map[VK_RIGHT] = Rml::Input::KI_RIGHT; - key_identifier_map[VK_DOWN] = Rml::Input::KI_DOWN; - key_identifier_map[VK_SELECT] = Rml::Input::KI_SELECT; - key_identifier_map[VK_PRINT] = Rml::Input::KI_PRINT; - key_identifier_map[VK_EXECUTE] = Rml::Input::KI_EXECUTE; - key_identifier_map[VK_SNAPSHOT] = Rml::Input::KI_SNAPSHOT; - key_identifier_map[VK_INSERT] = Rml::Input::KI_INSERT; - key_identifier_map[VK_DELETE] = Rml::Input::KI_DELETE; - key_identifier_map[VK_HELP] = Rml::Input::KI_HELP; - - key_identifier_map[VK_LWIN] = Rml::Input::KI_LWIN; - key_identifier_map[VK_RWIN] = Rml::Input::KI_RWIN; - key_identifier_map[VK_APPS] = Rml::Input::KI_APPS; - - key_identifier_map[VK_SLEEP] = Rml::Input::KI_SLEEP; - - key_identifier_map[VK_NUMPAD0] = Rml::Input::KI_NUMPAD0; - key_identifier_map[VK_NUMPAD1] = Rml::Input::KI_NUMPAD1; - key_identifier_map[VK_NUMPAD2] = Rml::Input::KI_NUMPAD2; - key_identifier_map[VK_NUMPAD3] = Rml::Input::KI_NUMPAD3; - key_identifier_map[VK_NUMPAD4] = Rml::Input::KI_NUMPAD4; - key_identifier_map[VK_NUMPAD5] = Rml::Input::KI_NUMPAD5; - key_identifier_map[VK_NUMPAD6] = Rml::Input::KI_NUMPAD6; - key_identifier_map[VK_NUMPAD7] = Rml::Input::KI_NUMPAD7; - key_identifier_map[VK_NUMPAD8] = Rml::Input::KI_NUMPAD8; - key_identifier_map[VK_NUMPAD9] = Rml::Input::KI_NUMPAD9; - key_identifier_map[VK_MULTIPLY] = Rml::Input::KI_MULTIPLY; - key_identifier_map[VK_ADD] = Rml::Input::KI_ADD; - key_identifier_map[VK_SEPARATOR] = Rml::Input::KI_SEPARATOR; - key_identifier_map[VK_SUBTRACT] = Rml::Input::KI_SUBTRACT; - key_identifier_map[VK_DECIMAL] = Rml::Input::KI_DECIMAL; - key_identifier_map[VK_DIVIDE] = Rml::Input::KI_DIVIDE; - key_identifier_map[VK_F1] = Rml::Input::KI_F1; - key_identifier_map[VK_F2] = Rml::Input::KI_F2; - key_identifier_map[VK_F3] = Rml::Input::KI_F3; - key_identifier_map[VK_F4] = Rml::Input::KI_F4; - key_identifier_map[VK_F5] = Rml::Input::KI_F5; - key_identifier_map[VK_F6] = Rml::Input::KI_F6; - key_identifier_map[VK_F7] = Rml::Input::KI_F7; - key_identifier_map[VK_F8] = Rml::Input::KI_F8; - key_identifier_map[VK_F9] = Rml::Input::KI_F9; - key_identifier_map[VK_F10] = Rml::Input::KI_F10; - key_identifier_map[VK_F11] = Rml::Input::KI_F11; - key_identifier_map[VK_F12] = Rml::Input::KI_F12; - key_identifier_map[VK_F13] = Rml::Input::KI_F13; - key_identifier_map[VK_F14] = Rml::Input::KI_F14; - key_identifier_map[VK_F15] = Rml::Input::KI_F15; - key_identifier_map[VK_F16] = Rml::Input::KI_F16; - key_identifier_map[VK_F17] = Rml::Input::KI_F17; - key_identifier_map[VK_F18] = Rml::Input::KI_F18; - key_identifier_map[VK_F19] = Rml::Input::KI_F19; - key_identifier_map[VK_F20] = Rml::Input::KI_F20; - key_identifier_map[VK_F21] = Rml::Input::KI_F21; - key_identifier_map[VK_F22] = Rml::Input::KI_F22; - key_identifier_map[VK_F23] = Rml::Input::KI_F23; - key_identifier_map[VK_F24] = Rml::Input::KI_F24; - - key_identifier_map[VK_NUMLOCK] = Rml::Input::KI_NUMLOCK; - key_identifier_map[VK_SCROLL] = Rml::Input::KI_SCROLL; - - key_identifier_map[VK_OEM_NEC_EQUAL] = Rml::Input::KI_OEM_NEC_EQUAL; - - key_identifier_map[VK_OEM_FJ_JISHO] = Rml::Input::KI_OEM_FJ_JISHO; - key_identifier_map[VK_OEM_FJ_MASSHOU] = Rml::Input::KI_OEM_FJ_MASSHOU; - key_identifier_map[VK_OEM_FJ_TOUROKU] = Rml::Input::KI_OEM_FJ_TOUROKU; - key_identifier_map[VK_OEM_FJ_LOYA] = Rml::Input::KI_OEM_FJ_LOYA; - key_identifier_map[VK_OEM_FJ_ROYA] = Rml::Input::KI_OEM_FJ_ROYA; - - key_identifier_map[VK_SHIFT] = Rml::Input::KI_LSHIFT; - key_identifier_map[VK_CONTROL] = Rml::Input::KI_LCONTROL; - key_identifier_map[VK_MENU] = Rml::Input::KI_LMENU; - - key_identifier_map[VK_BROWSER_BACK] = Rml::Input::KI_BROWSER_BACK; - key_identifier_map[VK_BROWSER_FORWARD] = Rml::Input::KI_BROWSER_FORWARD; - key_identifier_map[VK_BROWSER_REFRESH] = Rml::Input::KI_BROWSER_REFRESH; - key_identifier_map[VK_BROWSER_STOP] = Rml::Input::KI_BROWSER_STOP; - key_identifier_map[VK_BROWSER_SEARCH] = Rml::Input::KI_BROWSER_SEARCH; - key_identifier_map[VK_BROWSER_FAVORITES] = Rml::Input::KI_BROWSER_FAVORITES; - key_identifier_map[VK_BROWSER_HOME] = Rml::Input::KI_BROWSER_HOME; - - key_identifier_map[VK_VOLUME_MUTE] = Rml::Input::KI_VOLUME_MUTE; - key_identifier_map[VK_VOLUME_DOWN] = Rml::Input::KI_VOLUME_DOWN; - key_identifier_map[VK_VOLUME_UP] = Rml::Input::KI_VOLUME_UP; - key_identifier_map[VK_MEDIA_NEXT_TRACK] = Rml::Input::KI_MEDIA_NEXT_TRACK; - key_identifier_map[VK_MEDIA_PREV_TRACK] = Rml::Input::KI_MEDIA_PREV_TRACK; - key_identifier_map[VK_MEDIA_STOP] = Rml::Input::KI_MEDIA_STOP; - key_identifier_map[VK_MEDIA_PLAY_PAUSE] = Rml::Input::KI_MEDIA_PLAY_PAUSE; - key_identifier_map[VK_LAUNCH_MAIL] = Rml::Input::KI_LAUNCH_MAIL; - key_identifier_map[VK_LAUNCH_MEDIA_SELECT] = Rml::Input::KI_LAUNCH_MEDIA_SELECT; - key_identifier_map[VK_LAUNCH_APP1] = Rml::Input::KI_LAUNCH_APP1; - key_identifier_map[VK_LAUNCH_APP2] = Rml::Input::KI_LAUNCH_APP2; - - key_identifier_map[VK_OEM_1] = Rml::Input::KI_OEM_1; - key_identifier_map[VK_OEM_PLUS] = Rml::Input::KI_OEM_PLUS; - key_identifier_map[VK_OEM_COMMA] = Rml::Input::KI_OEM_COMMA; - key_identifier_map[VK_OEM_MINUS] = Rml::Input::KI_OEM_MINUS; - key_identifier_map[VK_OEM_PERIOD] = Rml::Input::KI_OEM_PERIOD; - key_identifier_map[VK_OEM_2] = Rml::Input::KI_OEM_2; - key_identifier_map[VK_OEM_3] = Rml::Input::KI_OEM_3; - - key_identifier_map[VK_OEM_4] = Rml::Input::KI_OEM_4; - key_identifier_map[VK_OEM_5] = Rml::Input::KI_OEM_5; - key_identifier_map[VK_OEM_6] = Rml::Input::KI_OEM_6; - key_identifier_map[VK_OEM_7] = Rml::Input::KI_OEM_7; - key_identifier_map[VK_OEM_8] = Rml::Input::KI_OEM_8; - - key_identifier_map[VK_OEM_AX] = Rml::Input::KI_OEM_AX; - key_identifier_map[VK_OEM_102] = Rml::Input::KI_OEM_102; - key_identifier_map[VK_ICO_HELP] = Rml::Input::KI_ICO_HELP; - key_identifier_map[VK_ICO_00] = Rml::Input::KI_ICO_00; - - key_identifier_map[VK_PROCESSKEY] = Rml::Input::KI_PROCESSKEY; - - key_identifier_map[VK_ICO_CLEAR] = Rml::Input::KI_ICO_CLEAR; - - key_identifier_map[VK_ATTN] = Rml::Input::KI_ATTN; - key_identifier_map[VK_CRSEL] = Rml::Input::KI_CRSEL; - key_identifier_map[VK_EXSEL] = Rml::Input::KI_EXSEL; - key_identifier_map[VK_EREOF] = Rml::Input::KI_EREOF; - key_identifier_map[VK_PLAY] = Rml::Input::KI_PLAY; - key_identifier_map[VK_ZOOM] = Rml::Input::KI_ZOOM; - key_identifier_map[VK_PA1] = Rml::Input::KI_PA1; - key_identifier_map[VK_OEM_CLEAR] = Rml::Input::KI_OEM_CLEAR; -} - -Rml::String 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 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; -} diff --git a/Samples/shell/src/win32/ShellRenderInterfaceExtensionsOpenGL_Win32.cpp b/Samples/shell/src/win32/ShellRenderInterfaceExtensionsOpenGL_Win32.cpp deleted file mode 100644 index 71c853bbf..000000000 --- a/Samples/shell/src/win32/ShellRenderInterfaceExtensionsOpenGL_Win32.cpp +++ /dev/null @@ -1,152 +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 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 -#include -#include -#include -#include -#include -#include -#include - - -void ShellRenderInterfaceOpenGL::SetViewport(int width, int height) -{ - if(m_width != width || m_height != height) { - Rml::Matrix4f projection, view; - - m_width = width; - m_height = height; - - glViewport(0, 0, width, height); - projection = Rml::Matrix4f::ProjectOrtho(0, (float)width, (float)height, 0, -10000, 10000); - glMatrixMode(GL_PROJECTION); - glLoadMatrixf(projection.data()); - view = Rml::Matrix4f::Identity(); - glMatrixMode(GL_MODELVIEW); - glLoadMatrixf(view.data()); - } -} - -bool ShellRenderInterfaceOpenGL::AttachToNative(void *nativeWindow) -{ - this->render_context = nullptr; - this->window_handle = (HWND)nativeWindow; - this->device_context = GetDC(this->window_handle); - if (this->device_context == nullptr) - { - Shell::DisplayError("Could not get device context."); - return false; - } - - PIXELFORMATDESCRIPTOR pixel_format_descriptor; - memset(&pixel_format_descriptor, 0, sizeof(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(this->device_context, &pixel_format_descriptor); - if (pixel_format == 0) - { - Shell::DisplayError("Could not choose 32-bit pixel format."); - return false; - } - - if (SetPixelFormat(this->device_context, pixel_format, &pixel_format_descriptor) == FALSE) - { - Shell::DisplayError("Could not set pixel format."); - return false; - } - - this->render_context = wglCreateContext(this->device_context); - if (this->render_context == nullptr) - { - Shell::DisplayError("Could not create OpenGL rendering context."); - return false; - } - - // Activate the rendering context. - if (wglMakeCurrent(this->device_context, this->render_context) == FALSE) - { - Shell::DisplayError("Unable to make rendering context current."); - return false; - } - - // Set up the GL state. - glClearColor(0, 0, 0, 1); - glEnableClientState(GL_VERTEX_ARRAY); - glEnableClientState(GL_COLOR_ARRAY); - - glEnable(GL_BLEND); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - - glMatrixMode(GL_PROJECTION); - glLoadIdentity(); - glMatrixMode(GL_MODELVIEW); - glLoadIdentity(); - - return true; -} - -void ShellRenderInterfaceOpenGL::DetachFromNative() -{ - // Shutdown OpenGL - if (this->render_context != nullptr) - { - wglMakeCurrent(nullptr, nullptr); - wglDeleteContext(this->render_context); - this->render_context = nullptr; - } - - if (this->device_context != nullptr) - { - ReleaseDC(this->window_handle, this->device_context); - this->device_context = nullptr; - } -} - -void ShellRenderInterfaceOpenGL::PrepareRenderBuffer() -{ - glClear(GL_COLOR_BUFFER_BIT); -} - -void ShellRenderInterfaceOpenGL::PresentRenderBuffer() -{ - // Flips the OpenGL buffers. - SwapBuffers(this->device_context); - RMLUI_FrameMark; -} diff --git a/Samples/shell/src/win32/ShellWin32.cpp b/Samples/shell/src/win32/ShellWin32.cpp deleted file mode 100644 index ea949d405..000000000 --- a/Samples/shell/src/win32/ShellWin32.cpp +++ /dev/null @@ -1,533 +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 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 -#include -#include -#include "ShellFileInterface.h" -#include -#include -#include -#include - -static LRESULT CALLBACK WindowProcedure(HWND window_handle, UINT message, WPARAM w_param, LPARAM l_param); - -static Rml::Context* context = nullptr; -static ShellRenderInterfaceExtensions* shell_renderer = nullptr; - -static bool activated = true; -static bool running = false; -static std::wstring instance_name; -static HWND window_handle = nullptr; -static HINSTANCE instance_handle = nullptr; - -static bool has_dpi_support = false; -static UINT window_dpi = USER_DEFAULT_SCREEN_DPI; -static int window_width = 0; -static int window_height = 0; - -static double time_frequency; -static LARGE_INTEGER time_startup; - -static Rml::UniquePtr file_interface; - -static HCURSOR cursor_default = nullptr; -static HCURSOR cursor_move = nullptr; -static HCURSOR cursor_pointer = nullptr; -static HCURSOR cursor_resize= nullptr; -static HCURSOR cursor_cross = nullptr; -static HCURSOR cursor_text = nullptr; -static HCURSOR cursor_unavailable = nullptr; - - -#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 ProcSetProcessDpiAwarenessContext procSetProcessDpiAwarenessContext = NULL; -static ProcGetDpiForWindow procGetDpiForWindow = NULL; -static ProcAdjustWindowRectExForDpi procAdjustWindowRectExForDpi = NULL; - -static void UpdateDpi() -{ - if (has_dpi_support) - { - UINT dpi = procGetDpiForWindow(window_handle); - if (dpi != 0) - { - window_dpi = dpi; - if (context) - context->SetDensityIndependentPixelRatio(Shell::GetDensityIndependentPixelRatio()); - } - } -} - -static void UpdateWindowDimensions(int width = 0, int height = 0) -{ - if (width > 0) - window_width = width; - if (height > 0) - window_height = height; - if (context) - context->SetDimensions(Rml::Vector2i(window_width, window_height)); - if (shell_renderer) - shell_renderer->SetViewport(window_width, window_height); -} - -bool Shell::Initialise() -{ - instance_handle = GetModuleHandle(nullptr); - InputWin32::Initialise(); - - 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); - - Rml::String root = FindSamplesRoot(); - bool result = !root.empty(); - - file_interface = Rml::MakeUnique(root); - Rml::SetFileInterface(file_interface.get()); - - // See if we have Per Monitor V2 DPI awareness. Requires Windows 10, version 1703. - // 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" - ); - - has_dpi_support = (procSetProcessDpiAwarenessContext != NULL && procGetDpiForWindow != NULL && procAdjustWindowRectExForDpi != NULL); - - return result; -} - -void Shell::Shutdown() -{ - InputWin32::Shutdown(); - - file_interface.reset(); -} - -Rml::String Shell::FindSamplesRoot() -{ - const char* candidate_paths[] = { "", "..\\Samples\\", "..\\..\\Samples\\", "..\\..\\..\\Samples\\", "..\\..\\..\\..\\Samples\\" }; - - // Fetch the path of the executable, test the candidate paths appended to that. - char executable_file_name[MAX_PATH]; - if (GetModuleFileNameA(instance_handle, executable_file_name, MAX_PATH) >= MAX_PATH && - GetLastError() == ERROR_INSUFFICIENT_BUFFER) - { - executable_file_name[0] = 0; - } - - Rml::String executable_path(executable_file_name); - executable_path = executable_path.substr(0, executable_path.rfind('\\') + 1); - - // We assume we have found the correct path if we can find the lookup file from it - const char* lookup_file = "assets\\rml.rcss"; - - for(const char* relative_path : candidate_paths) - { - Rml::String absolute_path = executable_path + relative_path; - - if (PathFileExistsA(Rml::String(absolute_path + lookup_file).c_str())) - { - char canonical_path[MAX_PATH]; - if (!PathCanonicalizeA(canonical_path, absolute_path.c_str())) - canonical_path[0] = 0; - - return Rml::String(canonical_path); - } - } - - return Rml::String(); -} - - -bool Shell::OpenWindow(const char* in_name, ShellRenderInterfaceExtensions *_shell_renderer, unsigned int width, unsigned int height, bool allow_resize) -{ - // Activate Per Monitor V2. - if (has_dpi_support && !procSetProcessDpiAwarenessContext(DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2)) - { - has_dpi_support = false; - } - - WNDCLASSW window_class; - - const std::wstring name = ConvertToUTF16(Rml::String(in_name)); - - // Fill out the window class struct. - window_class.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC; - window_class.lpfnWndProc = WindowProcedure; - window_class.cbClsExtra = 0; - window_class.cbWndExtra = 0; - window_class.hInstance = instance_handle; - window_class.hIcon = LoadIcon(nullptr, IDI_WINLOGO); - window_class.hCursor = cursor_default; - window_class.hbrBackground = nullptr; - window_class.lpszMenuName = nullptr; - window_class.lpszClassName = name.data(); - - if (!RegisterClassW(&window_class)) - { - DisplayError("Could not register window class."); - - CloseWindow(); - return false; - } - - 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("Could not create window."); - CloseWindow(); - - return false; - } - - window_width = width; - window_height = height; - - UpdateDpi(); - window_width = (width * window_dpi) / USER_DEFAULT_SCREEN_DPI; - window_height = (height * window_dpi) / USER_DEFAULT_SCREEN_DPI; - - instance_name = name; - - 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 into account the edges - RECT window_rect; - window_rect.top = 0; - window_rect.left = 0; - window_rect.right = window_width; - window_rect.bottom = window_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); - - if (_shell_renderer != nullptr) - { - shell_renderer = _shell_renderer; - if(!shell_renderer->AttachToNative(window_handle)) - { - CloseWindow(); - return false; - } - } - - UpdateWindowDimensions(); - - // Resize the window. - SetWindowPos(window_handle, HWND_TOP, 0, 0, window_rect.right - window_rect.left, window_rect.bottom - window_rect.top, SWP_NOACTIVATE); - - // Display the new window - ShowWindow(window_handle, SW_SHOW); - SetForegroundWindow(window_handle); - SetFocus(window_handle); - - return true; -} - -void Shell::CloseWindow() -{ - if(shell_renderer) { - shell_renderer->DetachFromNative(); - } - - DestroyWindow(window_handle); - UnregisterClassW((LPCWSTR)instance_name.data(), instance_handle); -} - -// Returns a platform-dependent handle to the window. -void* Shell::GetWindowHandle() -{ - return window_handle; -} - -void Shell::EventLoop(ShellIdleFunction idle_function) -{ - MSG message; - running = true; - - // Loop on PeekMessage() / GetMessage() until exit has been requested. - while (running) - { - if (PeekMessage(&message, nullptr, 0, 0, PM_NOREMOVE)) - { - GetMessage(&message, nullptr, 0, 0); - - TranslateMessage(&message); - DispatchMessage(&message); - } - - idle_function(); - } -} - -void Shell::RequestExit() -{ - running = false; -} - -void Shell::DisplayError(const char* fmt, ...) -{ - const int buffer_size = 1024; - char buffer[buffer_size]; - va_list argument_list; - - // Print the message to the buffer. - va_start(argument_list, fmt); - int len = vsnprintf(buffer, buffer_size - 2, fmt, argument_list); - if ( len < 0 || len > buffer_size - 2 ) - { - len = buffer_size - 2; - } - buffer[len] = '\n'; - buffer[len + 1] = '\0'; - va_end(argument_list); - - MessageBoxW(window_handle, ConvertToUTF16(buffer).c_str(), L"Shell Error", MB_OK); -} - -void Shell::Log(const char* fmt, ...) -{ - const int buffer_size = 1024; - char buffer[buffer_size]; - va_list argument_list; - - // Print the message to the buffer. - va_start(argument_list, fmt); - int len = vsnprintf(buffer, buffer_size - 2, fmt, argument_list); - if ( len < 0 || len > buffer_size - 2 ) - { - len = buffer_size - 2; - } - buffer[len] = '\n'; - buffer[len + 1] = '\0'; - va_end(argument_list); - - OutputDebugStringW(ConvertToUTF16(buffer).c_str()); -} - -double Shell::GetElapsedTime() -{ - LARGE_INTEGER counter; - QueryPerformanceCounter(&counter); - - return double(counter.QuadPart - time_startup.QuadPart) * time_frequency; -} - -void Shell::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 Shell::SetClipboardText(const Rml::String& text_utf8) -{ - if (window_handle) - { - if (!OpenClipboard(window_handle)) - return; - - EmptyClipboard(); - - const std::wstring text = 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 Shell::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 = ConvertToUTF8(clipboard_text); - GlobalUnlock(clipboard_data); - - CloseClipboard(); - } -} - -void Shell::SetContext(Rml::Context* new_context) -{ - context = new_context; - UpdateDpi(); - UpdateWindowDimensions(); -} - -float Shell::GetDensityIndependentPixelRatio() -{ - return float(window_dpi) / float(USER_DEFAULT_SCREEN_DPI); -} - -static LRESULT CALLBACK WindowProcedure(HWND local_window_handle, UINT message, WPARAM w_param, LPARAM l_param) -{ - // See what kind of message we've got. - switch (message) - { - case WM_ACTIVATE: - { - if (LOWORD(w_param) != WA_INACTIVE) - { - activated = true; - } - else - { - activated = false; - } - } - break; - - // When the window closes, request exit - case WM_CLOSE: - { - running = false; - return 0; - } - break; - - case WM_SIZE: - { - int width = LOWORD(l_param); - int height = HIWORD(l_param); - UpdateWindowDimensions(width, height); - } - break; - - case WM_DPICHANGED: - { - UpdateDpi(); - - RECT* const 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); - } - break; - - default: - { - InputWin32::ProcessWindowsEvent(local_window_handle, message, w_param, l_param); - } - break; - } - - // All unhandled messages go to DefWindowProc. - return DefWindowProc(local_window_handle, message, w_param, l_param); -} diff --git a/Samples/shell/src/x11/InputX11.cpp b/Samples/shell/src/x11/InputX11.cpp deleted file mode 100644 index c09b9a504..000000000 --- a/Samples/shell/src/x11/InputX11.cpp +++ /dev/null @@ -1,402 +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 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 -#include -#include -#include -#include -#include -#include -#ifdef HAS_X11XKBLIB -#include -#endif // HAS_X11XKBLIB -#include -#include -#include - -static void InitialiseKeymap(); -static int GetKeyModifierState(int x_state); - -static const int KEYMAP_SIZE = 256; -static Rml::Input::KeyIdentifier key_identifier_map[KEYMAP_SIZE]; - -#ifdef HAS_X11XKBLIB -static bool has_xkblib = false; -#endif // HAS_X11XKBLIB - -static int min_keycode, max_keycode, keysyms_per_keycode; -static KeySym *x11_key_mapping = nullptr; - -bool InputX11::Initialise() -{ - InitialiseKeymap(); - return true; -} - -void InputX11::Shutdown() -{ -} - -void InputX11::InitialiseX11Keymap(Display *display) -{ - RMLUI_ASSERT(display != nullptr); - -#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. - 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(!has_xkblib) -#endif // HAS_X11XKBLIB - { - XDisplayKeycodes(display, &min_keycode, &max_keycode); - - RMLUI_ASSERT(x11_key_mapping != nullptr); - x11_key_mapping = XGetKeyboardMapping(display, min_keycode, max_keycode + 1 - min_keycode, &keysyms_per_keycode); - } -} - -void InputX11::ProcessXEvent(Display* display, const XEvent& event) -{ - // Process all mouse and keyboard events - switch (event.type) - { - case ButtonPress: - { - int button_index; - - switch (event.xbutton.button) - { - case Button1: button_index = 0; break; - case Button2: button_index = 2; break; - case Button3: button_index = 1; break; - case Button4: context->ProcessMouseWheel(-1, GetKeyModifierState(event.xbutton.state)); return; - case Button5: context->ProcessMouseWheel(1, GetKeyModifierState(event.xbutton.state)); return; - default: return; - } - - context->ProcessMouseButtonDown(button_index, GetKeyModifierState(event.xbutton.state)); - } - break; - - case ButtonRelease: - { - int button_index; - - switch (event.xbutton.button) - { - case Button1: button_index = 0; break; - case Button2: button_index = 2; break; - case Button3: button_index = 1; break; - default: return; - } - - context->ProcessMouseButtonUp(button_index, GetKeyModifierState(event.xbutton.state)); - } - break; - - case MotionNotify: - context->ProcessMouseMove(event.xmotion.x, event.xmotion.y, GetKeyModifierState(event.xmotion.state)); - break; - - case KeyPress: - { - int group_index = 0; // this is always 0 for our limited example - Rml::Input::KeyIdentifier key_identifier; -#ifdef HAS_X11XKBLIB - if(has_xkblib) - { - KeySym sym = XkbKeycodeToKeysym(display, event.xkey.keycode, 0, group_index); - - key_identifier = key_identifier_map[sym & 0xFF]; - } - else -#endif // HAS_X11XKBLIB - { - KeySym sym = x11_key_mapping[(event.xkey.keycode - min_keycode) * keysyms_per_keycode + group_index]; - - KeySym lower_sym, upper_sym; - XConvertCase(sym, &lower_sym, &upper_sym); - - key_identifier = key_identifier_map[lower_sym & 0xFF]; - } - - const int key_modifier_state = GetKeyModifierState(event.xkey.state); - - // Check for special key combinations. - if (key_identifier == Rml::Input::KI_F8) - { - Rml::Debugger::SetVisible(!Rml::Debugger::IsVisible()); - } - else - { - bool propagates = false; - - // No special shortcut, pass the key on to the context. - 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)) - context->ProcessTextInput(character); - - // Check for low-priority key combinations that are only activated if not already consumed by the context. - if (propagates && key_identifier == Rml::Input::KI_R && key_modifier_state & Rml::Input::KM_CTRL) - { - for (int i = 0; i < context->GetNumDocuments(); i++) - { - Rml::ElementDocument* document = context->GetDocument(i); - const Rml::String& src = document->GetSourceURL(); - if (src.size() > 4 && src.substr(src.size() - 4) == ".rml") - { - document->ReloadStyleSheet(); - } - } - } - } - } - break; - - case KeyRelease: - { - int group_index = 0; // this is always 0 for our limited example - Rml::Input::KeyIdentifier key_identifier; -#ifdef HAS_X11XKBLIB - if(has_xkblib) - { - KeySym sym = XkbKeycodeToKeysym(display, event.xkey.keycode, 0, group_index); - - key_identifier = key_identifier_map[sym & 0xFF]; - } - else -#endif // HAS_X11XKBLIB - { - KeySym sym = x11_key_mapping[(event.xkey.keycode - min_keycode) * keysyms_per_keycode + group_index]; - - KeySym lower_sym, upper_sym; - XConvertCase(sym, &lower_sym, &upper_sym); - - key_identifier = key_identifier_map[lower_sym & 0xFF]; - } - - int key_modifier_state = GetKeyModifierState(event.xkey.state); - if (key_identifier != Rml::Input::KI_UNKNOWN) - context->ProcessKeyUp(key_identifier, key_modifier_state); - } - break; - } -} - -static int GetKeyModifierState(int x_state) -{ - int key_modifier_state = 0; - - if (x_state & ShiftMask) - key_modifier_state |= Rml::Input::KM_SHIFT; - - if (x_state & LockMask) - key_modifier_state |= Rml::Input::KM_CAPSLOCK; - - if (x_state & ControlMask) - key_modifier_state |= Rml::Input::KM_CTRL; - - if (x_state & Mod5Mask) - key_modifier_state |= Rml::Input::KM_ALT; - - if (x_state & Mod2Mask) - key_modifier_state |= Rml::Input::KM_NUMLOCK; - - return key_modifier_state; -} - -static void InitialiseKeymap() -{ - // Initialise the key map with default values. - memset(key_identifier_map, 0, sizeof(key_identifier_map)); - - key_identifier_map[XK_BackSpace & 0xFF] = Rml::Input::KI_BACK; - key_identifier_map[XK_Tab & 0xFF] = Rml::Input::KI_TAB; - key_identifier_map[XK_Clear & 0xFF] = Rml::Input::KI_CLEAR; - key_identifier_map[XK_Return & 0xFF] = Rml::Input::KI_RETURN; - key_identifier_map[XK_Pause & 0xFF] = Rml::Input::KI_PAUSE; - key_identifier_map[XK_Scroll_Lock & 0xFF] = Rml::Input::KI_SCROLL; - key_identifier_map[XK_Escape & 0xFF] = Rml::Input::KI_ESCAPE; - key_identifier_map[XK_Delete & 0xFF] = Rml::Input::KI_DELETE; - - key_identifier_map[XK_Kanji & 0xFF] = Rml::Input::KI_KANJI; -// key_identifier_map[XK_Muhenkan & 0xFF] = Rml::Input::; /* Cancel Conversion */ -// key_identifier_map[XK_Henkan_Mode & 0xFF] = Rml::Input::; /* Start/Stop Conversion */ -// key_identifier_map[XK_Henkan & 0xFF] = Rml::Input::; /* Alias for Henkan_Mode */ -// key_identifier_map[XK_Romaji & 0xFF] = Rml::Input::; /* to Romaji */ -// key_identifier_map[XK_Hiragana & 0xFF] = Rml::Input::; /* to Hiragana */ -// key_identifier_map[XK_Katakana & 0xFF] = Rml::Input::; /* to Katakana */ -// key_identifier_map[XK_Hiragana_Katakana & 0xFF] = Rml::Input::; /* Hiragana/Katakana toggle */ -// key_identifier_map[XK_Zenkaku & 0xFF] = Rml::Input::; /* to Zenkaku */ -// key_identifier_map[XK_Hankaku & 0xFF] = Rml::Input::; /* to Hankaku */ -// key_identifier_map[XK_Zenkaku_Hankaku & 0xFF] = Rml::Input::; /* Zenkaku/Hankaku toggle */ - key_identifier_map[XK_Touroku & 0xFF] = Rml::Input::KI_OEM_FJ_TOUROKU; - key_identifier_map[XK_Massyo & 0xFF] = Rml::Input::KI_OEM_FJ_MASSHOU; -// key_identifier_map[XK_Kana_Lock & 0xFF] = Rml::Input::; /* Kana Lock */ -// key_identifier_map[XK_Kana_Shift & 0xFF] = Rml::Input::; /* Kana Shift */ -// key_identifier_map[XK_Eisu_Shift & 0xFF] = Rml::Input::; /* Alphanumeric Shift */ -// key_identifier_map[XK_Eisu_toggle & 0xFF] = Rml::Input::; /* Alphanumeric toggle */ - - key_identifier_map[XK_Home & 0xFF] = Rml::Input::KI_HOME; - key_identifier_map[XK_Left & 0xFF] = Rml::Input::KI_LEFT; - key_identifier_map[XK_Up & 0xFF] = Rml::Input::KI_UP; - key_identifier_map[XK_Right & 0xFF] = Rml::Input::KI_RIGHT; - key_identifier_map[XK_Down & 0xFF] = Rml::Input::KI_DOWN; - key_identifier_map[XK_Prior & 0xFF] = Rml::Input::KI_PRIOR; - key_identifier_map[XK_Next & 0xFF] = Rml::Input::KI_NEXT; - key_identifier_map[XK_End & 0xFF] = Rml::Input::KI_END; - key_identifier_map[XK_Begin & 0xFF] = Rml::Input::KI_HOME; - - key_identifier_map[XK_Print & 0xFF] = Rml::Input::KI_SNAPSHOT; - key_identifier_map[XK_Insert & 0xFF] = Rml::Input::KI_INSERT; - key_identifier_map[XK_Num_Lock & 0xFF] = Rml::Input::KI_NUMLOCK; - - key_identifier_map[XK_KP_Space & 0xFF] = Rml::Input::KI_SPACE; - key_identifier_map[XK_KP_Tab & 0xFF] = Rml::Input::KI_TAB; - key_identifier_map[XK_KP_Enter & 0xFF] = Rml::Input::KI_NUMPADENTER; - key_identifier_map[XK_KP_F1 & 0xFF] = Rml::Input::KI_F1; - key_identifier_map[XK_KP_F2 & 0xFF] = Rml::Input::KI_F2; - key_identifier_map[XK_KP_F3 & 0xFF] = Rml::Input::KI_F3; - key_identifier_map[XK_KP_F4 & 0xFF] = Rml::Input::KI_F4; - key_identifier_map[XK_KP_Home & 0xFF] = Rml::Input::KI_NUMPAD7; - key_identifier_map[XK_KP_Left & 0xFF] = Rml::Input::KI_NUMPAD4; - key_identifier_map[XK_KP_Up & 0xFF] = Rml::Input::KI_NUMPAD8; - key_identifier_map[XK_KP_Right & 0xFF] = Rml::Input::KI_NUMPAD6; - key_identifier_map[XK_KP_Down & 0xFF] = Rml::Input::KI_NUMPAD2; - key_identifier_map[XK_KP_Prior & 0xFF] = Rml::Input::KI_NUMPAD9; - key_identifier_map[XK_KP_Next & 0xFF] = Rml::Input::KI_NUMPAD3; - key_identifier_map[XK_KP_End & 0xFF] = Rml::Input::KI_NUMPAD1; - key_identifier_map[XK_KP_Begin & 0xFF] = Rml::Input::KI_NUMPAD5; - key_identifier_map[XK_KP_Insert & 0xFF] = Rml::Input::KI_NUMPAD0; - key_identifier_map[XK_KP_Delete & 0xFF] = Rml::Input::KI_DECIMAL; - key_identifier_map[XK_KP_Equal & 0xFF] = Rml::Input::KI_OEM_NEC_EQUAL; - key_identifier_map[XK_KP_Multiply & 0xFF] = Rml::Input::KI_MULTIPLY; - key_identifier_map[XK_KP_Add & 0xFF] = Rml::Input::KI_ADD; - key_identifier_map[XK_KP_Separator & 0xFF] = Rml::Input::KI_SEPARATOR; - key_identifier_map[XK_KP_Subtract & 0xFF] = Rml::Input::KI_SUBTRACT; - key_identifier_map[XK_KP_Decimal & 0xFF] = Rml::Input::KI_DECIMAL; - key_identifier_map[XK_KP_Divide & 0xFF] = Rml::Input::KI_DIVIDE; - - key_identifier_map[XK_F1 & 0xFF] = Rml::Input::KI_F1; - key_identifier_map[XK_F2 & 0xFF] = Rml::Input::KI_F2; - key_identifier_map[XK_F3 & 0xFF] = Rml::Input::KI_F3; - key_identifier_map[XK_F4 & 0xFF] = Rml::Input::KI_F4; - key_identifier_map[XK_F5 & 0xFF] = Rml::Input::KI_F5; - key_identifier_map[XK_F6 & 0xFF] = Rml::Input::KI_F6; - key_identifier_map[XK_F7 & 0xFF] = Rml::Input::KI_F7; - key_identifier_map[XK_F8 & 0xFF] = Rml::Input::KI_F8; - key_identifier_map[XK_F9 & 0xFF] = Rml::Input::KI_F9; - key_identifier_map[XK_F10 & 0xFF] = Rml::Input::KI_F10; - key_identifier_map[XK_F11 & 0xFF] = Rml::Input::KI_F11; - key_identifier_map[XK_F12 & 0xFF] = Rml::Input::KI_F12; - key_identifier_map[XK_F13 & 0xFF] = Rml::Input::KI_F13; - key_identifier_map[XK_F14 & 0xFF] = Rml::Input::KI_F14; - key_identifier_map[XK_F15 & 0xFF] = Rml::Input::KI_F15; - key_identifier_map[XK_F16 & 0xFF] = Rml::Input::KI_F16; - key_identifier_map[XK_F17 & 0xFF] = Rml::Input::KI_F17; - key_identifier_map[XK_F18 & 0xFF] = Rml::Input::KI_F18; - key_identifier_map[XK_F19 & 0xFF] = Rml::Input::KI_F19; - key_identifier_map[XK_F20 & 0xFF] = Rml::Input::KI_F20; - key_identifier_map[XK_F21 & 0xFF] = Rml::Input::KI_F21; - key_identifier_map[XK_F22 & 0xFF] = Rml::Input::KI_F22; - key_identifier_map[XK_F23 & 0xFF] = Rml::Input::KI_F23; - key_identifier_map[XK_F24 & 0xFF] = Rml::Input::KI_F24; - - key_identifier_map[XK_Shift_L & 0xFF] = Rml::Input::KI_LSHIFT; - key_identifier_map[XK_Shift_R & 0xFF] = Rml::Input::KI_RSHIFT; - key_identifier_map[XK_Control_L & 0xFF] = Rml::Input::KI_LCONTROL; - key_identifier_map[XK_Control_R & 0xFF] = Rml::Input::KI_RCONTROL; - key_identifier_map[XK_Caps_Lock & 0xFF] = Rml::Input::KI_CAPITAL; - - key_identifier_map[XK_Alt_L & 0xFF] = Rml::Input::KI_LMENU; - key_identifier_map[XK_Alt_R & 0xFF] = Rml::Input::KI_RMENU; - - key_identifier_map[XK_space & 0xFF] = Rml::Input::KI_SPACE; - key_identifier_map[XK_apostrophe & 0xFF] = Rml::Input::KI_OEM_7; - key_identifier_map[XK_comma & 0xFF] = Rml::Input::KI_OEM_COMMA; - key_identifier_map[XK_minus & 0xFF] = Rml::Input::KI_OEM_MINUS; - key_identifier_map[XK_period & 0xFF] = Rml::Input::KI_OEM_PERIOD; - key_identifier_map[XK_slash & 0xFF] = Rml::Input::KI_OEM_2; - key_identifier_map[XK_0 & 0xFF] = Rml::Input::KI_0; - key_identifier_map[XK_1 & 0xFF] = Rml::Input::KI_1; - key_identifier_map[XK_2 & 0xFF] = Rml::Input::KI_2; - key_identifier_map[XK_3 & 0xFF] = Rml::Input::KI_3; - key_identifier_map[XK_4 & 0xFF] = Rml::Input::KI_4; - key_identifier_map[XK_5 & 0xFF] = Rml::Input::KI_5; - key_identifier_map[XK_6 & 0xFF] = Rml::Input::KI_6; - key_identifier_map[XK_7 & 0xFF] = Rml::Input::KI_7; - key_identifier_map[XK_8 & 0xFF] = Rml::Input::KI_8; - key_identifier_map[XK_9 & 0xFF] = Rml::Input::KI_9; - key_identifier_map[XK_semicolon & 0xFF] = Rml::Input::KI_OEM_1; - key_identifier_map[XK_equal & 0xFF] = Rml::Input::KI_OEM_PLUS; - key_identifier_map[XK_bracketleft & 0xFF] = Rml::Input::KI_OEM_4; - key_identifier_map[XK_backslash & 0xFF] = Rml::Input::KI_OEM_5; - key_identifier_map[XK_bracketright & 0xFF] = Rml::Input::KI_OEM_6; - key_identifier_map[XK_grave & 0xFF] = Rml::Input::KI_OEM_3; - key_identifier_map[XK_a & 0xFF] = Rml::Input::KI_A; - key_identifier_map[XK_b & 0xFF] = Rml::Input::KI_B; - key_identifier_map[XK_c & 0xFF] = Rml::Input::KI_C; - key_identifier_map[XK_d & 0xFF] = Rml::Input::KI_D; - key_identifier_map[XK_e & 0xFF] = Rml::Input::KI_E; - key_identifier_map[XK_f & 0xFF] = Rml::Input::KI_F; - key_identifier_map[XK_g & 0xFF] = Rml::Input::KI_G; - key_identifier_map[XK_h & 0xFF] = Rml::Input::KI_H; - key_identifier_map[XK_i & 0xFF] = Rml::Input::KI_I; - key_identifier_map[XK_j & 0xFF] = Rml::Input::KI_J; - key_identifier_map[XK_k & 0xFF] = Rml::Input::KI_K; - key_identifier_map[XK_l & 0xFF] = Rml::Input::KI_L; - key_identifier_map[XK_m & 0xFF] = Rml::Input::KI_M; - key_identifier_map[XK_n & 0xFF] = Rml::Input::KI_N; - key_identifier_map[XK_o & 0xFF] = Rml::Input::KI_O; - key_identifier_map[XK_p & 0xFF] = Rml::Input::KI_P; - key_identifier_map[XK_q & 0xFF] = Rml::Input::KI_Q; - key_identifier_map[XK_r & 0xFF] = Rml::Input::KI_R; - key_identifier_map[XK_s & 0xFF] = Rml::Input::KI_S; - key_identifier_map[XK_t & 0xFF] = Rml::Input::KI_T; - key_identifier_map[XK_u & 0xFF] = Rml::Input::KI_U; - key_identifier_map[XK_v & 0xFF] = Rml::Input::KI_V; - key_identifier_map[XK_w & 0xFF] = Rml::Input::KI_W; - key_identifier_map[XK_x & 0xFF] = Rml::Input::KI_X; - key_identifier_map[XK_y & 0xFF] = Rml::Input::KI_Y; - key_identifier_map[XK_z & 0xFF] = Rml::Input::KI_Z; -} diff --git a/Samples/shell/src/x11/ShellRenderInterfaceExtensionsOpenGL_X11.cpp b/Samples/shell/src/x11/ShellRenderInterfaceExtensionsOpenGL_X11.cpp deleted file mode 100644 index c1eb3af06..000000000 --- a/Samples/shell/src/x11/ShellRenderInterfaceExtensionsOpenGL_X11.cpp +++ /dev/null @@ -1,112 +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 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 -#include -#include -#include -#include -#include -#include "../../include/Shell.h" - - -void ShellRenderInterfaceOpenGL::SetViewport(int width, int height) -{ - if(m_width != width || m_height != height) { - Rml::Matrix4f projection, view; - - m_width = width; - m_height = height; - - glViewport(0, 0, width, height); - projection = Rml::Matrix4f::ProjectOrtho(0, (float)width, (float)height, 0, -10000, 10000); - glMatrixMode(GL_PROJECTION); - glLoadMatrixf(projection.data()); - view = Rml::Matrix4f::Identity(); - glMatrixMode(GL_MODELVIEW); - glLoadMatrixf(view.data()); - } -} - -bool ShellRenderInterfaceOpenGL::AttachToNative(void *nativeWindow) -{ - this->nwData.display = ((__X11NativeWindowData *)nativeWindow)->display; - this->nwData.window = ((__X11NativeWindowData *)nativeWindow)->window; - this->nwData.visual_info = ((__X11NativeWindowData *)nativeWindow)->visual_info; - - this->gl_context = glXCreateContext(nwData.display, nwData.visual_info, nullptr, GL_TRUE); - if (this->gl_context == nullptr) - return false; - - if (!glXMakeCurrent(nwData.display, nwData.window, this->gl_context)) - return false; - - if (!glXIsDirect(nwData.display, this->gl_context)) - Shell::Log("OpenGL context does not support direct rendering; performance is likely to be poor."); - - Window root_window; - int x, y; - unsigned int width, height; - unsigned int border_width, depth; - XGetGeometry(nwData.display, nwData.window, &root_window, &x, &y, &width, &height, &border_width, &depth); - - // Set up the GL state. - glClearColor(0, 0, 0, 1); - glEnableClientState(GL_VERTEX_ARRAY); - glEnableClientState(GL_COLOR_ARRAY); - - glEnable(GL_BLEND); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - - glMatrixMode(GL_PROJECTION); - glLoadIdentity(); - glOrtho(0, 1024, 768, 0, -1, 1); - - glMatrixMode(GL_MODELVIEW); - glLoadIdentity(); - return true; -} - -void ShellRenderInterfaceOpenGL::DetachFromNative() -{ - // Shutdown OpenGL - glXMakeCurrent(this->nwData.display, 0L, nullptr); - glXDestroyContext(this->nwData.display, this->gl_context); - this->gl_context = nullptr; -} - -void ShellRenderInterfaceOpenGL::PrepareRenderBuffer() -{ - glClear(GL_COLOR_BUFFER_BIT); -} - -void ShellRenderInterfaceOpenGL::PresentRenderBuffer() -{ - // Flips the OpenGL buffers. - glXSwapBuffers(this->nwData.display, this->nwData.window); -} diff --git a/Samples/shell/src/x11/ShellX11.cpp b/Samples/shell/src/x11/ShellX11.cpp deleted file mode 100644 index 7091107ad..000000000 --- a/Samples/shell/src/x11/ShellX11.cpp +++ /dev/null @@ -1,558 +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 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 -#include -#include -#include -#include -#include "ShellFileInterface.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -static Rml::Context* context = nullptr; -static ShellRenderInterfaceExtensions* shell_renderer = nullptr; - -static bool running = false; -static int screen = -1; -static timeval start_time; -static Rml::String clipboard_text; -static int window_width = 0; -static int window_height = 0; - -static Rml::UniquePtr file_interface; - -static Display* display = nullptr; -static XVisualInfo* visual_info = nullptr; -static Window window = 0; - -static Cursor cursor_default = 0; -static Cursor cursor_move = 0; -static Cursor cursor_pointer = 0; -static Cursor cursor_resize = 0; -static Cursor cursor_cross = 0; -static Cursor cursor_text = 0; -static Cursor cursor_unavailable = 0; - -static Atom XA_atom = 4; -static Atom XA_STRING_atom = 31; -static Atom UTF8_atom; -static Atom CLIPBOARD_atom; -static Atom XSEL_DATA_atom; -static Atom TARGETS_atom; -static Atom TEXT_atom; - - -static void UpdateWindowDimensions(int width = 0, int height = 0) -{ - if (width > 0) - window_width = width; - if (height > 0) - window_height = height; - if (context) - context->SetDimensions(Rml::Vector2i(window_width, window_height)); - if (shell_renderer) - shell_renderer->SetViewport(window_width, window_height); -} - -static bool isRegularFile(const Rml::String& path) -{ - struct stat sb; - return (stat(path.c_str(), &sb) == 0 && S_ISREG(sb.st_mode)); -} - -void XCopy(const Rml::String &clipboard_data, const XEvent &event) -{ - Atom format; - if (UTF8_atom) { - format = UTF8_atom; - } else { - format = 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 XPaste(Atom target_atom, Rml::String &clipboard_data) -{ - XEvent event; - - // 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, &event); - - if (event.type == SelectionNotify) { - if (event.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 (event.xselection.selection == CLIPBOARD_atom) { - int actual_format; - unsigned long bytes_after, nitems; - char *prop = nullptr; - Atom actual_type; - XGetWindowProperty( - event.xselection.display, - event.xselection.requestor, - event.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(event.xselection.display, event.xselection.requestor, event.xselection.property); - return true; - } - } - - return false; -} - -bool Shell::Initialise() -{ - gettimeofday(&start_time, nullptr); - if (!InputX11::Initialise()) - return false; - - Rml::String root = FindSamplesRoot(); - bool result = !root.empty(); - - file_interface = Rml::MakeUnique(root); - Rml::SetFileInterface(file_interface.get()); - - return result; -} - -void Shell::Shutdown() -{ - InputX11::Shutdown(); - - file_interface.reset(); -} - -Rml::String Shell::FindSamplesRoot() -{ - char executable_file_name[PATH_MAX]; - ssize_t len = readlink("/proc/self/exe", executable_file_name, PATH_MAX); - if (len == -1) { - printf("Unable to determine the executable path!\n"); - executable_file_name[0] = 0; - } else { - // readlink() does not append a null byte to buf. - executable_file_name[len] = 0; - } - Rml::String executable_path = Rml::String(executable_file_name); - executable_path = executable_path.substr(0, executable_path.rfind("/") + 1); - - // We assume we have found the correct path if we can find the lookup file from it. - const char* lookup_file = "assets/rml.rcss"; - - // For "../Samples/" to be valid we must be in the Build directory. - // If "../" is valid we are probably in the installation directory. - // Some build setups may nest the executables deeper in a build directory, try them last. - const char* candidate_paths[] = { "", "../", "../Samples/", "../../Samples/", "../../../Samples/", "../../../../Samples/" }; - - for (const char* relative_path : candidate_paths) - { - Rml::String absolute_path = executable_path + relative_path; - Rml::String absolute_lookup_file = absolute_path + lookup_file; - - if (isRegularFile(absolute_lookup_file)) - { - return absolute_path; - } - } - - printf("Unable to find the path to the samples root!\n"); - - return Rml::String(); -} - -bool Shell::OpenWindow(const char* name, ShellRenderInterfaceExtensions *_shell_renderer, unsigned int width, unsigned int height, bool allow_resize) -{ - display = XOpenDisplay(0); - if (display == nullptr) - return false; - - window_width = width; - window_height = height; - - // This initialise they keyboard to keycode mapping system of X11 - // itself. It must be done here as it needs to query the connected - // X server display for information about its install keymap abilities. - InputX11::InitialiseX11Keymap(display); - - 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}; - - visual_info = glXChooseVisual(display, screen, attribute_list); - if (visual_info == nullptr) - { - 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 = 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 == nullptr) - { - 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; - - // {ass the size hints to the window manager. - XSetWMNormalHints(display, window, win_size_hints); - - // Free the size buffer - XFree(win_size_hints); - } - } - - { - // 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); - - // Set the window title and show the window. - XSetStandardProperties(display, window, name, "", 0L, nullptr, 0, nullptr); - XMapRaised(display, window); - - shell_renderer = _shell_renderer; - if(shell_renderer != nullptr) - { - struct __X11NativeWindowData nwData; - nwData.display = display; - nwData.window = window; - nwData.visual_info = visual_info; - return shell_renderer->AttachToNative(&nwData); - } - return true; -} - -void Shell::CloseWindow() -{ - if(shell_renderer != nullptr) - { - shell_renderer->DetachFromNative(); - } - - if (display != nullptr) - { - XCloseDisplay(display); - display = nullptr; - } -} - -// Returns a platform-dependent handle to the window. -void* Shell::GetWindowHandle() -{ - return nullptr; -} - -void Shell::EventLoop(ShellIdleFunction idle_function) -{ - running = true; - - // Loop on Peek/GetMessage until and exit has been requested - while (running) - { - while (XPending(display) > 0) - { - XEvent event; - char *event_type = nullptr; - XNextEvent(display, &event); - - switch (event.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. - event_type = XGetAtomName(display, event.xclient.message_type); - if (strcmp(event_type, "WM_PROTOCOLS") == 0) - running = false; - XFree(event_type); - event_type = nullptr; - } - break; - - case ConfigureNotify: - { - int x = event.xconfigure.width; - int y = event.xconfigure.height; - - UpdateWindowDimensions(x, y); - } - break; - - case SelectionRequest: - { - if (XGetSelectionOwner(display, CLIPBOARD_atom) == window && - event.xselectionrequest.selection == CLIPBOARD_atom - ) { - XCopy(clipboard_text, event); - } - } - break; - - default: - { - InputX11::ProcessXEvent(display, event); - } - } - } - - idle_function(); - } -} - -void Shell::RequestExit() -{ - running = false; -} - -void Shell::DisplayError(const char* fmt, ...) -{ - const int buffer_size = 1024; - char buffer[buffer_size]; - va_list argument_list; - - // Print the message to the buffer. - va_start(argument_list, fmt); - int len = vsnprintf(buffer, buffer_size - 2, fmt, argument_list); - if ( len < 0 || len > buffer_size - 2 ) - { - len = buffer_size - 2; - } - buffer[len] = '\n'; - buffer[len + 1] = '\0'; - va_end(argument_list); - - printf("%s", buffer); -} - -void Shell::Log(const char* fmt, ...) -{ - const int buffer_size = 1024; - char buffer[buffer_size]; - va_list argument_list; - - // Print the message to the buffer. - va_start(argument_list, fmt); - int len = vsnprintf(buffer, buffer_size - 2, fmt, argument_list); - if ( len < 0 || len > buffer_size - 2 ) - { - len = buffer_size - 2; - } - buffer[len] = '\n'; - buffer[len + 1] = '\0'; - va_end(argument_list); - - printf("%s", buffer); -} - -// Returns the seconds that have elapsed since program startup. -double Shell::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 Shell::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 Shell::SetClipboardText(const Rml::String& text) -{ - // interface with system clipboard - clipboard_text = text; - XSetSelectionOwner(display, CLIPBOARD_atom, window, 0); -} - -void Shell::GetClipboardText(Rml::String& text) -{ - // interface with system clipboard - if (XGetSelectionOwner(display, CLIPBOARD_atom) != window) { - if(!UTF8_atom || !XPaste(UTF8_atom, text)) { - // fallback - XPaste(XA_STRING_atom, text); - } - } else { - text = clipboard_text; - } -} - -void Shell::SetContext(Rml::Context* new_context) -{ - context = new_context; - UpdateWindowDimensions(); -} diff --git a/Samples/tutorial/datagrid/src/DecoratorDefender.cpp b/Samples/tutorial/datagrid/src/DecoratorDefender.cpp index 723343296..1e62966b7 100644 --- a/Samples/tutorial/datagrid/src/DecoratorDefender.cpp +++ b/Samples/tutorial/datagrid/src/DecoratorDefender.cpp @@ -10,14 +10,13 @@ */ #include "DecoratorDefender.h" -#include #include +#include +#include +#include #include -#include -DecoratorDefender::~DecoratorDefender() -{ -} +DecoratorDefender::~DecoratorDefender() {} bool DecoratorDefender::Initialise(const Rml::Texture& texture) { @@ -52,24 +51,14 @@ void DecoratorDefender::RenderElement(Rml::Element* element, Rml::DecoratorDataH Rml::Vector2f position = element->GetAbsoluteOffset(Rml::Box::PADDING); Rml::Vector2f size = element->GetBox().GetSize(Rml::Box::PADDING); - 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); - glVertex2f(position.x + size.x, position.y); - glTexCoord2f(0, 0); + Rml::Vertex vertices[4]; + int indices[6]; + Rml::GeometryUtilities::GenerateQuad(vertices, indices, position, size, Rml::Colourb(255)); - glEnd(); - glColor4ub(255, 255, 255, 255); + render_interface->RenderGeometry(vertices, 4, indices, 6, texture, Rml::Vector2f(0.f)); + } } diff --git a/Samples/tutorial/datagrid/src/main.cpp b/Samples/tutorial/datagrid/src/main.cpp index 14e6509c3..05bee8cab 100644 --- a/Samples/tutorial/datagrid/src/main.cpp +++ b/Samples/tutorial/datagrid/src/main.cpp @@ -9,82 +9,53 @@ * */ +#include "DecoratorInstancerDefender.h" +#include "HighScores.h" #include #include -#include +#include #include -#include -#include "DecoratorInstancerDefender.h" -#include "HighScores.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 -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 +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; -#ifdef RMLUI_PLATFORM_WIN32 - AllocConsole(); -#endif - - 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("Datagrid Tutorial", shell_renderer, 1024, 768, true)) + // Constructs the system and render interfaces, creates a window, and attaches the renderer. + if (!Backend::Initialize("Datagrid Tutorial", window_width, window_height, true)) { Shell::Shutdown(); return -1; } - // RmlUi initialisation. - Rml::SetRenderInterface(&opengl_renderer); - opengl_renderer.SetViewport(1024,768); - - 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(1024, 768)); - 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 the defender decorator. DecoratorInstancerDefender decorator_instancer_defender; @@ -101,7 +72,17 @@ 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(); + } // Shut down the high scores. HighScores::Shutdown(); @@ -109,7 +90,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; diff --git a/Samples/tutorial/datagrid_tree/src/DecoratorDefender.cpp b/Samples/tutorial/datagrid_tree/src/DecoratorDefender.cpp index 723343296..1e62966b7 100644 --- a/Samples/tutorial/datagrid_tree/src/DecoratorDefender.cpp +++ b/Samples/tutorial/datagrid_tree/src/DecoratorDefender.cpp @@ -10,14 +10,13 @@ */ #include "DecoratorDefender.h" -#include #include +#include +#include +#include #include -#include -DecoratorDefender::~DecoratorDefender() -{ -} +DecoratorDefender::~DecoratorDefender() {} bool DecoratorDefender::Initialise(const Rml::Texture& texture) { @@ -52,24 +51,14 @@ void DecoratorDefender::RenderElement(Rml::Element* element, Rml::DecoratorDataH Rml::Vector2f position = element->GetAbsoluteOffset(Rml::Box::PADDING); Rml::Vector2f size = element->GetBox().GetSize(Rml::Box::PADDING); - 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); - glVertex2f(position.x + size.x, position.y); - glTexCoord2f(0, 0); + Rml::Vertex vertices[4]; + int indices[6]; + Rml::GeometryUtilities::GenerateQuad(vertices, indices, position, size, Rml::Colourb(255)); - glEnd(); - glColor4ub(255, 255, 255, 255); + render_interface->RenderGeometry(vertices, 4, indices, 6, texture, Rml::Vector2f(0.f)); + } } diff --git a/Samples/tutorial/datagrid_tree/src/main.cpp b/Samples/tutorial/datagrid_tree/src/main.cpp index 5fc970a75..906e625d3 100644 --- a/Samples/tutorial/datagrid_tree/src/main.cpp +++ b/Samples/tutorial/datagrid_tree/src/main.cpp @@ -9,86 +9,54 @@ * */ -#include -#include -#include -#include -#include #include "DecoratorInstancerDefender.h" #include "HighScores.h" #include "HighScoresShipFormatter.h" - -Rml::Context* context = nullptr; - -ShellRenderInterfaceExtensions *shell_renderer; - -void GameLoop() -{ - context->Update(); - - shell_renderer->PrepareRenderBuffer(); - context->Render(); - shell_renderer->PresentRenderBuffer(); -} +#include +#include +#include +#include #if defined RMLUI_PLATFORM_WIN32 -#include -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 +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("Datagrid Tree Tutorial", shell_renderer, window_width, window_height, true)) + // Constructs the system and render interfaces, creates a window, and attaches the renderer. + if (!Backend::Initialize("Datagrid Tree Tutorial", 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 the defender decorator. DecoratorInstancerDefender decorator_instancer_defender; @@ -108,7 +76,17 @@ 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(); + } // Shut down the high scores. HighScores::Shutdown(); @@ -116,7 +94,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; diff --git a/Samples/tutorial/drag/src/main.cpp b/Samples/tutorial/drag/src/main.cpp index a698f35c3..42f0b5eb9 100644 --- a/Samples/tutorial/drag/src/main.cpp +++ b/Samples/tutorial/drag/src/main.cpp @@ -9,84 +9,52 @@ * */ +#include "Inventory.h" #include #include -#include +#include #include -#include -#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 -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 +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("Drag Tutorial", shell_renderer, window_width, window_height, true)) + // Constructs the system and render interfaces, creates a window, and attaches the renderer. + if (!Backend::Initialize("Drag Tutorial", 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); @@ -98,7 +66,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; @@ -106,7 +84,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; diff --git a/Samples/tutorial/template/src/main.cpp b/Samples/tutorial/template/src/main.cpp index 3926c19ce..dfddd56ac 100644 --- a/Samples/tutorial/template/src/main.cpp +++ b/Samples/tutorial/template/src/main.cpp @@ -11,92 +11,70 @@ #include #include -#include +#include #include -#include - -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 -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 +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("Template Tutorial", shell_renderer, window_width, window_height, true)) + // Constructs the system and render interfaces, creates a window, and attaches the renderer. + if (!Backend::Initialize("Template Tutorial", 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 tutorial document. - if (Rml::ElementDocument * document = context->LoadDocument("tutorial/template/data/tutorial.rml")) + if (Rml::ElementDocument* document = context->LoadDocument("tutorial/template/data/tutorial.rml")) 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; diff --git a/Source/SVG/ElementSVG.cpp b/Source/SVG/ElementSVG.cpp index ee9f27ae8..c1b44d337 100644 --- a/Source/SVG/ElementSVG.cpp +++ b/Source/SVG/ElementSVG.cpp @@ -37,6 +37,7 @@ #include "../../Include/RmlUi/Core/SystemInterface.h" #include #include +#include namespace Rml { diff --git a/Tests/Source/Benchmarks/ElementDocument.cpp b/Tests/Source/Benchmarks/ElementDocument.cpp index 94e3d84b2..e5379036c 100644 --- a/Tests/Source/Benchmarks/ElementDocument.cpp +++ b/Tests/Source/Benchmarks/ElementDocument.cpp @@ -132,9 +132,9 @@ TEST_CASE("elementdocument") ElementDocument* document = context->LoadDocumentFromMemory(document_rml); document->Show(); context->Update(); - TestsShell::PrepareRenderBuffer(); + TestsShell::BeginFrame(); context->Render(); - TestsShell::PresentRenderBuffer(); + TestsShell::PresentFrame(); document->Close(); context->Update(); }); @@ -176,9 +176,9 @@ TEST_CASE("elementdocument") ElementDocument* document = context->LoadDocumentFromMemory(document_rml); document->Show(); context->Update(); - TestsShell::PrepareRenderBuffer(); + TestsShell::BeginFrame(); context->Render(); - TestsShell::PresentRenderBuffer(); + TestsShell::PresentFrame(); document->Close(); context->Update(); }); diff --git a/Tests/Source/Common/TestsInterface.cpp b/Tests/Source/Common/TestsInterface.cpp index 9da083a8d..198aaa63e 100644 --- a/Tests/Source/Common/TestsInterface.cpp +++ b/Tests/Source/Common/TestsInterface.cpp @@ -27,9 +27,15 @@ */ #include "TestsInterface.h" +#include #include #include +double TestsSystemInterface::GetElapsedTime() +{ + return 0.0; +} + bool TestsSystemInterface::LogMessage(Rml::Log::Type type, const Rml::String& message) { static const char* message_type_str[Rml::Log::Type::LT_MAX] = { "Always", "Error", "Assert", "Warning", "Info", "Debug" }; diff --git a/Tests/Source/Common/TestsInterface.h b/Tests/Source/Common/TestsInterface.h index 3909bc60e..c810529e3 100644 --- a/Tests/Source/Common/TestsInterface.h +++ b/Tests/Source/Common/TestsInterface.h @@ -29,13 +29,14 @@ #ifndef RMLUI_TESTS_TESTSINTERFACE_H #define RMLUI_TESTS_TESTSINTERFACE_H -#include #include +#include +#include - -class TestsSystemInterface : public ShellSystemInterface -{ +class TestsSystemInterface : public Rml::SystemInterface { public: + double GetElapsedTime() override; + bool LogMessage(Rml::Log::Type type, const Rml::String& message) override; // Checks and clears previously logged messages, then sets the number of expected @@ -49,9 +50,7 @@ class TestsSystemInterface : public ShellSystemInterface Rml::StringList warnings; }; - -class TestsRenderInterface : public Rml::RenderInterface -{ +class TestsRenderInterface : public Rml::RenderInterface { public: struct Counters { size_t render_calls; @@ -63,7 +62,8 @@ class TestsRenderInterface : public Rml::RenderInterface size_t set_transform; }; - void RenderGeometry(Rml::Vertex* vertices, int num_vertices, int* indices, int num_indices, Rml::TextureHandle texture, const Rml::Vector2f& translation) override; + 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; @@ -74,15 +74,12 @@ class TestsRenderInterface : public Rml::RenderInterface void SetTransform(const Rml::Matrix4f* transform) override; - const Counters& GetCounters() const { - return counters; - } + const Counters& GetCounters() const { return counters; } - void ResetCounters() { - counters = {}; - } + void ResetCounters() { counters = {}; } private: Counters counters = {}; }; + #endif diff --git a/Tests/Source/Common/TestsShell.cpp b/Tests/Source/Common/TestsShell.cpp index f8fac3c62..125630415 100644 --- a/Tests/Source/Common/TestsShell.cpp +++ b/Tests/Source/Common/TestsShell.cpp @@ -27,22 +27,19 @@ */ #include "TestsShell.h" +#include "TestsInterface.h" #include -#include -#include #include +#include +#include #include +#include #include -#include -#include -#include "TestsInterface.h" - #include // Uncomment the following to render to the shell window instead of the dummy renderer. Useful for viewing the result while building RML. //#define RMLUI_TESTS_USE_SHELL - namespace { const Rml::Vector2i window_size(1500, 800); @@ -53,8 +50,6 @@ namespace { TestsSystemInterface tests_system_interface; #ifdef RMLUI_TESTS_USE_SHELL - ShellRenderInterfaceOpenGL shell_render_interface; - class TestsShellEventListener : public Rml::EventListener { public: void ProcessEvent(Rml::Event& event) override @@ -65,7 +60,7 @@ namespace { // Will escape the current render loop if (key_identifier == Rml::Input::KI_ESCAPE || key_identifier == Rml::Input::KI_RETURN || key_identifier == Rml::Input::KI_NUMPADENTER) - Shell::RequestExit(); + Backend::RequestExit(); } } } shell_event_listener; @@ -73,41 +68,45 @@ namespace { // The tests renderer only collects statistics, does not render anything. TestsRenderInterface shell_render_interface; #endif -} +} // namespace -static void InitializeShell() -{ - // Initialize shell and create context. - if (!shell_initialized) + static void InitializeShell() { - shell_initialized = true; - - Rml::SetSystemInterface(&tests_system_interface); - Rml::SetRenderInterface(&shell_render_interface); - - REQUIRE(Rml::Initialise()); - shell_context = Rml::CreateContext("main", window_size); - - REQUIRE(Shell::Initialise()); - Shell::LoadFonts("assets/"); + // Initialize shell and create context. + if (!shell_initialized) + { + shell_initialized = true; + REQUIRE(Shell::Initialize()); #ifdef RMLUI_TESTS_USE_SHELL - // Also, create the window. + // Initialize the backend and launch a window. + REQUIRE(Backend::Initialize("RmlUi Tests", window_size.x, window_size.y, true)); - Rml::Debugger::Initialise(shell_context); - num_documents_begin = shell_context->GetNumDocuments(); + // Use our custom tests system interface. + Rml::SetSystemInterface(&tests_system_interface); + // However, use the backend's render interface. + Rml::SetRenderInterface(Backend::GetRenderInterface()); - REQUIRE(Shell::OpenWindow("RmlUi Tests", &shell_render_interface, window_size.x, window_size.y, true)); + REQUIRE(Rml::Initialise()); + shell_context = Rml::CreateContext("main", window_size); + Shell::LoadFonts(); - shell_render_interface.SetViewport(window_size.x, window_size.y); + Rml::Debugger::Initialise(shell_context); + num_documents_begin = shell_context->GetNumDocuments(); - ::Input::SetContext(shell_context); - Shell::SetContext(shell_context); + shell_context->GetRootElement()->AddEventListener(Rml::EventId::Keydown, &shell_event_listener, true); - shell_context->GetRootElement()->AddEventListener(Rml::EventId::Keydown, &shell_event_listener, true); +#else + // Set our custom system and render interfaces. + Rml::SetSystemInterface(&tests_system_interface); + Rml::SetRenderInterface(&shell_render_interface); + + REQUIRE(Rml::Initialise()); + shell_context = Rml::CreateContext("main", window_size); + Shell::LoadFonts(); #endif + } } -} Rml::Context* TestsShell::GetContext() @@ -116,17 +115,17 @@ Rml::Context* TestsShell::GetContext() return shell_context; } -void TestsShell::PrepareRenderBuffer() +void TestsShell::BeginFrame() { #ifdef RMLUI_TESTS_USE_SHELL - shell_render_interface.PrepareRenderBuffer(); + Backend::BeginFrame(); #endif } -void TestsShell::PresentRenderBuffer() +void TestsShell::PresentFrame() { #ifdef RMLUI_TESTS_USE_SHELL - shell_render_interface.PresentRenderBuffer(); + Backend::PresentFrame(); #endif } @@ -134,13 +133,16 @@ void TestsShell::RenderLoop() { REQUIRE(shell_context); -#if defined(RMLUI_TESTS_USE_SHELL) - Shell::EventLoop([]() { +#ifdef RMLUI_TESTS_USE_SHELL + bool running = true; + while (running) + { + running = Backend::ProcessEvents(shell_context, &Shell::ProcessKeyDownShortcuts); shell_context->Update(); - PrepareRenderBuffer(); + BeginFrame(); shell_context->Render(); - PresentRenderBuffer(); - }); + PresentFrame(); + } #else shell_context->Update(); shell_context->Render(); @@ -159,10 +161,10 @@ void TestsShell::ShutdownShell() Rml::Shutdown(); #ifdef RMLUI_TESTS_USE_SHELL - Shell::CloseWindow(); - Shell::Shutdown(); - Shell::SetContext(nullptr); + Backend::Shutdown(); #endif + + Shell::Shutdown(); shell_context = nullptr; shell_initialized = false; diff --git a/Tests/Source/Common/TestsShell.h b/Tests/Source/Common/TestsShell.h index 21b8be02b..cdc44acf0 100644 --- a/Tests/Source/Common/TestsShell.h +++ b/Tests/Source/Common/TestsShell.h @@ -37,8 +37,8 @@ namespace TestsShell { // Will initialize the shell and create a context on first use. Rml::Context* GetContext(); - void PrepareRenderBuffer(); - void PresentRenderBuffer(); + void BeginFrame(); + void PresentFrame(); // Render the current state of the context. Press 'escape' or 'return' to break out of the loop. // Useful for viewing documents while building the RML to benchmark. diff --git a/Tests/Source/VisualTests/CaptureScreen.cpp b/Tests/Source/VisualTests/CaptureScreen.cpp index 2096f9154..2ef9a0f2f 100644 --- a/Tests/Source/VisualTests/CaptureScreen.cpp +++ b/Tests/Source/VisualTests/CaptureScreen.cpp @@ -28,27 +28,25 @@ #include "CaptureScreen.h" #include "TestConfig.h" -#include -#include +#include +#include #include #include -#include +#include #include #define LODEPNG_NO_COMPILE_CPP - #include - -bool CaptureScreenshot(ShellRenderInterfaceOpenGL* shell_renderer, const Rml::String& filename, int clip_width) +bool CaptureScreenshot(const Rml::String& filename, int clip_width) { - using Image = ShellRenderInterfaceOpenGL::Image; + using Image = RendererExtensions::Image; - Image image_orig = shell_renderer->CaptureScreen(); + Image image_orig = RendererExtensions::CaptureScreen(); if (!image_orig.data) { - Rml::Log::Message(Rml::Log::LT_ERROR, "Could not capture screenshot from OpenGL window."); + Rml::Log::Message(Rml::Log::LT_ERROR, "Could not capture screenshot of window."); return false; } @@ -88,17 +86,15 @@ bool CaptureScreenshot(ShellRenderInterfaceOpenGL* shell_renderer, const Rml::St return true; } - struct DeferFree { unsigned char* ptr = nullptr; ~DeferFree() { free(ptr); } }; - -ComparisonResult CompareScreenToPreviousCapture( - ShellRenderInterfaceOpenGL* shell_renderer, const Rml::String& filename, bool write_diff_image, TextureGeometry* out_geometry) +ComparisonResult CompareScreenToPreviousCapture(Rml::RenderInterface* render_interface, const Rml::String& filename, bool write_diff_image, + TextureGeometry* out_geometry) { - using Image = ShellRenderInterfaceOpenGL::Image; + using Image = RendererExtensions::Image; const Rml::String input_path = GetCompareInputDirectory() + "/" + filename; @@ -120,7 +116,7 @@ ComparisonResult CompareScreenToPreviousCapture( // Optionally render the previous capture to a texture. if (out_geometry) { - if (!shell_renderer->GenerateTexture(out_geometry->texture_handle, data_ref, Rml::Vector2i((int)w_ref, (int)h_ref))) + if (!render_interface->GenerateTexture(out_geometry->texture_handle, data_ref, Rml::Vector2i((int)w_ref, (int)h_ref))) { ComparisonResult result; result.success = false; @@ -136,12 +132,12 @@ ComparisonResult CompareScreenToPreviousCapture( Rml::Vector2f((float)w_ref, (float)h_ref), colour, uv_top_left, uv_bottom_right, 0); } - Image screen = shell_renderer->CaptureScreen(); + Image screen = RendererExtensions::CaptureScreen(); if (!screen.data) { ComparisonResult result; result.success = false; - result.error_msg = "Could not capture screen from OpenGL window."; + result.error_msg = "Could not capture screenshot of window."; return result; } RMLUI_ASSERT(screen.num_components == 3); @@ -216,17 +212,17 @@ ComparisonResult CompareScreenToPreviousCapture( return result; } -void RenderTextureGeometry(ShellRenderInterfaceOpenGL* shell_renderer, TextureGeometry& geometry) +void RenderTextureGeometry(Rml::RenderInterface* render_interface, TextureGeometry& geometry) { if (geometry.texture_handle) - shell_renderer->RenderGeometry(geometry.vertices, 4, geometry.indices, 6, geometry.texture_handle, Rml::Vector2f(0, 0)); + render_interface->RenderGeometry(geometry.vertices, 4, geometry.indices, 6, geometry.texture_handle, Rml::Vector2f(0, 0)); } -void ReleaseTextureGeometry(ShellRenderInterfaceOpenGL* shell_renderer, TextureGeometry& geometry) +void ReleaseTextureGeometry(Rml::RenderInterface* render_interface, TextureGeometry& geometry) { if (geometry.texture_handle) { - shell_renderer->ReleaseTexture(geometry.texture_handle); + render_interface->ReleaseTexture(geometry.texture_handle); geometry.texture_handle = 0; } } diff --git a/Tests/Source/VisualTests/CaptureScreen.h b/Tests/Source/VisualTests/CaptureScreen.h index 36407c76b..2b10d7783 100644 --- a/Tests/Source/VisualTests/CaptureScreen.h +++ b/Tests/Source/VisualTests/CaptureScreen.h @@ -29,11 +29,10 @@ #ifndef RMLUI_TESTS_VISUALTESTS_CAPTURESCREEN_H #define RMLUI_TESTS_VISUALTESTS_CAPTURESCREEN_H +#include #include #include -class ShellRenderInterfaceOpenGL; - struct ComparisonResult { bool skipped = true; bool success = false; @@ -49,14 +48,13 @@ struct TextureGeometry { int indices[6] = {}; }; -bool CaptureScreenshot(ShellRenderInterfaceOpenGL* shell_renderer, const Rml::String& filename, int clip_width); - -ComparisonResult CompareScreenToPreviousCapture( - ShellRenderInterfaceOpenGL* shell_renderer, const Rml::String& filename, bool write_diff_image, TextureGeometry* out_geometry); +bool CaptureScreenshot(const Rml::String& filename, int clip_width); -void RenderTextureGeometry(ShellRenderInterfaceOpenGL* shell_renderer, TextureGeometry& geometry); +ComparisonResult CompareScreenToPreviousCapture(Rml::RenderInterface* render_interface, const Rml::String& filename, bool write_diff_image, + TextureGeometry* out_geometry); -void ReleaseTextureGeometry(ShellRenderInterfaceOpenGL* shell_renderer, TextureGeometry& geometry); +void RenderTextureGeometry(Rml::RenderInterface* render_interface, TextureGeometry& geometry); +void ReleaseTextureGeometry(Rml::RenderInterface* render_interface, TextureGeometry& geometry); #endif diff --git a/Tests/Source/VisualTests/TestConfig.cpp b/Tests/Source/VisualTests/TestConfig.cpp index f122efbe4..350993cff 100644 --- a/Tests/Source/VisualTests/TestConfig.cpp +++ b/Tests/Source/VisualTests/TestConfig.cpp @@ -30,14 +30,14 @@ #include #include #include - +#include Rml::String GetCompareInputDirectory() { #ifdef RMLUI_VISUAL_TESTS_COMPARE_DIRECTORY const Rml::String input_directory = Rml::String(RMLUI_VISUAL_TESTS_COMPARE_DIRECTORY); #else - const Rml::String input_directory = Shell::FindSamplesRoot() + "../Tests/Output"; + const Rml::String input_directory = PlatformExtensions::FindSamplesRoot() + "../Tests/Output"; #endif return input_directory; } @@ -47,14 +47,14 @@ Rml::String GetCaptureOutputDirectory() #ifdef RMLUI_VISUAL_TESTS_CAPTURE_DIRECTORY const Rml::String output_directory = Rml::String(RMLUI_VISUAL_TESTS_CAPTURE_DIRECTORY); #else - const Rml::String output_directory = Shell::FindSamplesRoot() + "../Tests/Output"; + const Rml::String output_directory = PlatformExtensions::FindSamplesRoot() + "../Tests/Output"; #endif return output_directory; } Rml::StringList GetTestInputDirectories() { - const Rml::String samples_root = Shell::FindSamplesRoot(); + const Rml::String samples_root = PlatformExtensions::FindSamplesRoot(); Rml::StringList directories = { samples_root + "../Tests/Data/VisualTests" }; diff --git a/Tests/Source/VisualTests/TestNavigator.cpp b/Tests/Source/VisualTests/TestNavigator.cpp index c7e39dc1e..4afa7bc5f 100644 --- a/Tests/Source/VisualTests/TestNavigator.cpp +++ b/Tests/Source/VisualTests/TestNavigator.cpp @@ -34,7 +34,6 @@ #include #include #include -#include #include // When capturing frames it seems we need to wait at least an extra frame for the newly submitted @@ -42,8 +41,10 @@ constexpr int iteration_wait_frame_count = 2; -TestNavigator::TestNavigator(ShellRenderInterfaceOpenGL* shell_renderer, Rml::Context* context, TestViewer* viewer, TestSuiteList test_suites, int start_index) - : shell_renderer(shell_renderer), context(context), viewer(viewer), test_suites(std::move(test_suites)) +TestNavigator::TestNavigator(Rml::RenderInterface* render_interface, Rml::Context* context, TestViewer* viewer, TestSuiteList test_suites, + int start_index) : + render_interface(render_interface), + context(context), viewer(viewer), test_suites(std::move(test_suites)) { RMLUI_ASSERT(context); RMLUI_ASSERTMSG(!this->test_suites.empty(), "At least one test suite is required."); @@ -51,7 +52,7 @@ TestNavigator::TestNavigator(ShellRenderInterfaceOpenGL* shell_renderer, Rml::Co context->GetRootElement()->AddEventListener(Rml::EventId::Keydown, this); context->GetRootElement()->AddEventListener(Rml::EventId::Textinput, this); context->GetRootElement()->AddEventListener(Rml::EventId::Change, this); - if(start_index > 0) + if (start_index > 0) CurrentSuite().SetIndex(start_index); LoadActiveTest(); } @@ -62,7 +63,7 @@ TestNavigator::~TestNavigator() context->GetRootElement()->RemoveEventListener(Rml::EventId::Keydown, this); context->GetRootElement()->RemoveEventListener(Rml::EventId::Textinput, this); context->GetRootElement()->RemoveEventListener(Rml::EventId::Change, this); - ReleaseTextureGeometry(shell_renderer, reference_geometry); + ReleaseTextureGeometry(render_interface, reference_geometry); } void TestNavigator::Update() @@ -110,8 +111,8 @@ void TestNavigator::Render() { if (show_reference && reference_geometry.texture_handle) { - shell_renderer->RenderGeometry( - reference_geometry.vertices, 4, reference_geometry.indices, 6, reference_geometry.texture_handle, Rml::Vector2f(0, 0)); + render_interface->RenderGeometry(reference_geometry.vertices, 4, reference_geometry.indices, 6, reference_geometry.texture_handle, + Rml::Vector2f(0, 0)); } } @@ -367,7 +368,7 @@ ComparisonResult TestNavigator::CompareCurrentView() { const Rml::String filename = GetImageFilenameFromCurrentTest(); - ComparisonResult result = CompareScreenToPreviousCapture(shell_renderer, filename, true, nullptr); + ComparisonResult result = CompareScreenToPreviousCapture(render_interface, filename, true, nullptr); return result; } @@ -377,7 +378,7 @@ bool TestNavigator::CaptureCurrentView() { const Rml::String filename = GetImageFilenameFromCurrentTest(); - bool result = CaptureScreenshot(shell_renderer, filename, 1060); + bool result = CaptureScreenshot(filename, 1060); return result; } @@ -562,14 +563,14 @@ void TestNavigator::ShowReference(bool show, bool clear) { if (clear) { - ReleaseTextureGeometry(shell_renderer, reference_geometry); + ReleaseTextureGeometry(render_interface, reference_geometry); reference_comparison = {}; } Rml::String error_msg; if (show && !reference_geometry.texture_handle) { - reference_comparison = CompareScreenToPreviousCapture(shell_renderer, GetImageFilenameFromCurrentTest(), false, &reference_geometry); + reference_comparison = CompareScreenToPreviousCapture(render_interface, GetImageFilenameFromCurrentTest(), false, &reference_geometry); if (!reference_comparison.success) error_msg = reference_comparison.error_msg; diff --git a/Tests/Source/VisualTests/TestNavigator.h b/Tests/Source/VisualTests/TestNavigator.h index 1bc750479..799c11ce8 100644 --- a/Tests/Source/VisualTests/TestNavigator.h +++ b/Tests/Source/VisualTests/TestNavigator.h @@ -35,11 +35,9 @@ #include #include -class ShellRenderInterfaceOpenGL; - class TestNavigator : public Rml::EventListener { public: - TestNavigator(ShellRenderInterfaceOpenGL* shell_renderer, Rml::Context* context, TestViewer* viewer, TestSuiteList test_suites, int start_index); + TestNavigator(Rml::RenderInterface* render_interface, Rml::Context* context, TestViewer* viewer, TestSuiteList test_suites, int start_index); ~TestNavigator(); void Update(); @@ -69,7 +67,7 @@ class TestNavigator : public Rml::EventListener { Rml::String GetImageFilenameFromCurrentTest(); - ShellRenderInterfaceOpenGL* shell_renderer; + Rml::RenderInterface* render_interface; Rml::Context* context; TestViewer* viewer; TestSuiteList test_suites; diff --git a/Tests/Source/VisualTests/TestViewer.cpp b/Tests/Source/VisualTests/TestViewer.cpp index f55385842..4c0cd3fd9 100644 --- a/Tests/Source/VisualTests/TestViewer.cpp +++ b/Tests/Source/VisualTests/TestViewer.cpp @@ -35,6 +35,7 @@ #include #include #include +#include #include #include #include @@ -67,9 +68,12 @@ class EventListenerLinks : public Rml::EventListener { if (event == Rml::EventId::Click) { - Shell::SetClipboardText(href); - hover_text->SetInnerRML("Copied to clipboard"); - hover_text->SetClass("confirmation", true); + if (Rml::SystemInterface* system_interface = Rml::GetSystemInterface()) + { + system_interface->SetClipboardText(href); + hover_text->SetInnerRML("Copied to clipboard"); + hover_text->SetClass("confirmation", true); + } } else if (event == Rml::EventId::Mouseover) { diff --git a/Tests/Source/VisualTests/main.cpp b/Tests/Source/VisualTests/main.cpp index 5c4a1bf38..8493d528e 100644 --- a/Tests/Source/VisualTests/main.cpp +++ b/Tests/Source/VisualTests/main.cpp @@ -26,44 +26,22 @@ * */ +#include "CaptureScreen.h" #include "TestConfig.h" -#include "TestViewer.h" #include "TestNavigator.h" -#include "CaptureScreen.h" #include "TestSuite.h" +#include "TestViewer.h" #include #include #include #include +#include +#include #include -#include -#include - - -Rml::Context* context = nullptr; -ShellRenderInterfaceOpenGL* shell_renderer = nullptr; -TestNavigator* g_navigator = nullptr; - -void GameLoop() -{ - context->Update(); - - shell_renderer->PrepareRenderBuffer(); - context->Render(); - - if (g_navigator) - g_navigator->Render(); - - shell_renderer->PresentRenderBuffer(); - - if (g_navigator) - g_navigator->Update(); -} - #if defined RMLUI_PLATFORM_WIN32 -#include -int APIENTRY WinMain(HINSTANCE RMLUI_UNUSED_PARAMETER(instance_handle), HINSTANCE RMLUI_UNUSED_PARAMETER(previous_instance_handle), char* command_line, int RMLUI_UNUSED_PARAMETER(command_show)) + #include +int APIENTRY WinMain(HINSTANCE /*instance_handle*/, HINSTANCE /*previous_instance_handle*/, char* command_line, int /*command_show*/) #else int main(int argc, char** argv) #endif @@ -71,43 +49,36 @@ int main(int argc, char** argv) int load_test_case_index = -1; #ifdef RMLUI_PLATFORM_WIN32 - RMLUI_UNUSED(instance_handle); - RMLUI_UNUSED(previous_instance_handle); - RMLUI_UNUSED(command_show); - load_test_case_index = std::atoi(command_line) - 1; #else if (argc > 1) load_test_case_index = std::atoi(argv[1]) - 1; #endif - int window_width = 1500; int window_height = 800; - 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("Visual tests", shell_renderer, window_width, window_height, true)) + // Constructs the system and render interfaces, creates a window, and attaches the renderer. + if (!Backend::Initialize("Visual tests", 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(); Shell::Shutdown(); @@ -115,10 +86,7 @@ int main(int argc, char** argv) } Rml::Debugger::Initialise(context); - Input::SetContext(context); - Shell::SetContext(context); - - Shell::LoadFonts("assets/"); + Shell::LoadFonts(); { const Rml::StringList directories = GetTestInputDirectories(); @@ -127,34 +95,39 @@ int main(int argc, char** argv) for (const Rml::String& directory : directories) { - const Rml::StringList files = Shell::ListFiles(directory, "rml"); + const Rml::StringList files = PlatformExtensions::ListFiles(directory, "rml"); if (files.empty()) - { Rml::Log::Message(Rml::Log::LT_WARNING, "Could not find any *.rml files in directory '%s'. Ignoring.", directory.c_str()); - } else - { test_suites.emplace_back(directory, std::move(files)); - } } RMLUI_ASSERTMSG(!test_suites.empty(), "RML test files directory not found or empty."); TestViewer viewer(context); - TestNavigator navigator(shell_renderer, context, &viewer, std::move(test_suites), load_test_case_index); - g_navigator = &navigator; + TestNavigator navigator(context->GetRenderInterface(), context, &viewer, std::move(test_suites), load_test_case_index); + + bool running = true; + while (running) + { + running = Backend::ProcessEvents(context, &Shell::ProcessKeyDownShortcuts); + + context->Update(); - Shell::EventLoop(GameLoop); + Backend::BeginFrame(); + context->Render(); + navigator.Render(); + Backend::PresentFrame(); - g_navigator = nullptr; + navigator.Update(); + } } Rml::Shutdown(); - - Shell::CloseWindow(); Shell::Shutdown(); + Backend::Shutdown(); return 0; } diff --git a/readme.md b/readme.md index bd81e05f6..cd376ec85 100644 --- a/readme.md +++ b/readme.md @@ -43,6 +43,35 @@ Documentation is located at https://mikke89.github.io/RmlUiDoc/ - File handling and the font engine can optionally be fully replaced by the user. +## Conformance + +RmlUi aims to support the most common and familiar features from HTML and CSS, while keeping the library light and performant. We do not aim to be fully compliant with CSS or HTML, in particular when it conflicts with lightness and performance. Users are generally expected to author documents specifically for RmlUi, but any experience and skills from web design should be transferable. + +RmlUi supports most of CSS2 with some CSS3 features such as + +- Animations and transitions +- Transforms (with full interpolation support) +- Flexbox layout +- Media queries +- Border radius + +and many of the common HTML elements including ``, `