Name Mode Size
..
glbackend.hpp 100644 4 kb
glbackend_default.hpp 100644 1 kb
glbackend_glfw.hpp 100644 4 kb
glbackend_sdl.hpp 100644 3 kb
glbackend_wxwidgets.hpp 100644 4 kb
README.md
# [`glbackend`][] A [C++11][]/[OpenGL][] \>=[1.0][] [backend][] library. Currently supported backends (one from each category listed under [Context/Window Toolkits][] on the OpenGL wiki): | Name | Category | Define | Include | Class | | -- | -- | -- | -- | -- | | [GLFW][] | Windowing/input | `GLBACKEND_GLFW` | `glbackend_glfw.hpp` | `BackendGLFW` | | [SDL2][] | Multimedia | `GLBACKEND_SDL` | `glbackend_sdl.hpp` | `BackendSDL` | | [wxWidgets][] | [Widget toolkit][] | `GLBACKEND_WXWIDGETS` | `glbackend_wxwidgets.hpp` | `BackendWxWidgets` | [`glbackend`]: https://git.rcrnstn.net/rcrnstn/glbackend [C++11]: https://en.wikipedia.org/wiki/C++11 [OpenGL]: https://en.wikipedia.org/wiki/OpenGL [1.0]: https://en.wikipedia.org/wiki/OpenGL#Version_history [backend]: https://www.khronos.org/opengl/wiki/Related_toolkits_and_APIs#OpenGL_initialization [Context/Window Toolkits]: https://www.khronos.org/opengl/wiki/Related_toolkits_and_APIs#Context/Window_Toolkits [GLFW]: https://www.glfw.org [SDL2]: https://www.libsdl.org [wxWidgets]: https://www.wxwidgets.org [Widget toolkit]: https://en.wikipedia.org/wiki/Widget_toolkit ## Usage ### Overview ```cpp #include <glbackend_default.hpp> constexpr auto size = GLBackend::Size{640, 480}; int main() { // Create. auto backend = GLBackendDefault("Default", size); // Render loop. backend.callback_render([&]() { glClearColor(1.0F, 0.0F, 0.0F, 0.5F); glClear(GL_COLOR_BUFFER_BIT); if (backend.key("Enter")) backend.tga_write("screenshot.tga"); if (backend.key("Escape")) backend.running(false); }); backend.run(); } ``` ### Global settings #### Errors After backend construction (see [Lifetime](#lifetime)) errors are non-fatal and are reported to the output configured with ``` using OutputCallback = std::function<void(std::string const & message)>; static std::ostream * output_stream(std::ostream * output_stream); static OutputCallback output_callback(OutputCallback output_callback); ``` (defaults to `std::cerr` and empty, respectively). The old values are returned. If the backend is constructed with `debug = true` (see [Lifetime](#lifetime)) and OpenGL \>=4.3 or the extension [`GL_KHR_debug`][] is available, OpenGL debug messages with a severity other than `GL_DEBUG_SEVERITY_NOTIFICATION` are also reported using the same output. The messages received from the OpenGL implementation are modified slightly to remove trailing whitespace and double quotes surrounding file names in lines starting with *"path":line*. [`GL_KHR_debug`]: https://www.khronos.org/registry/OpenGL/extensions/KHR/KHR_debug.txt #### File system If the value passed to ``` static std::string directory(std::string directory); ``` is non-empty it is prepended, with a separating `"/"`, to all relative paths (defined as paths not starting with `"/"`) given as arguments to other functions. The old value is returned. ### Lifetime Constructors [`throw`][] [`std::runtime_error`][] on failure, with a `what()` describing the error. To use a backend, instantiate the appropriate `Backend`-derived class. Several objects can be instantiated, using the same or different underlying backends. All the provided `Backend`-derived classes' constructors take the following arguments, in this order: - Window-related: - `std::string const & title`: The window title. - `int width`: The window width. - `int height`: The window height. - `bool fullscreen = false`: Whether or not to create a fullscreen window. - `bool transparent = false`: Whether or not to use the alpha channel of the default framebuffer to blend with the background. If this is enabled, window decorations are disabled and the window is kept on top of other windows. - [Context][]-related: - `bool debug = false`: If `false`, creates a [no error][] context. If `true`, creates a [debug context][], and enables [debug output][]. - `int samples = -1`: The number of samples used in [mutlisample][multisampling] anti-aliasing (MSAA) of the default framebuffer (`-1` lets the implementation decide). - `int version_major = -1`: The major version with which the OpenGL [context][] must be compatible (`-1` lets the implementation decide). - `int version_minor = -1`: The minor version with which the OpenGL [context][] must be compatible (`-1` lets the implementation decide). The relevant underlying backend is automatically initialized at instantiation. If no other code has initialized that backend, it is guaranteed to be terminated when the last instance is destroyed. It is backend-specific if the backend is terminated even if other code has initialized it. The provided `Backend`s create double buffered, 32 bit color (including alpha), 24 bit depth, 8 bit stencil OpenGL [context][]s. If the requested version is \>=3.2 a [forward compatible][] core context is created. The `Backend`s are move(-constructible)-only types. [`throw`]: https://en.cppreference.com/w/cpp/language/throw [`std::runtime_error`]: https://en.cppreference.com/w/cpp/error/runtime_error [context]: https://www.khronos.org/opengl/wiki/OpenGL_Context [debug context]: https://www.khronos.org/opengl/wiki/Debug_Context [debug output]: https://www.khronos.org/opengl/wiki/Debug_Output [no error]: https://www.khronos.org/opengl/wiki/OpenGL_Context#No_error_contexts [multisampling]: https://www.khronos.org/opengl/wiki/Multisampling [forward compatible]: https://www.khronos.org/opengl/wiki/OpenGL_Context#Forward_compatibility ### Info ``` std::string info() const; ``` returns information about the underlying backend. ### Context Each `Backend` instance has its own OpenGL [context][], which is made current at instantiation. If several `Backend`s are used, ``` void current(); ``` can be called to make the context of a specific one current. ### Render loop ``` void events(); ``` handles events from the underlying backend. ``` void swap(); ``` swaps the OpenGL default framebuffer. ``` bool running() const; bool running(bool running); ``` queries and sets, respectively, the window "running" state. ``` float time() const; float time(float time); ``` queries and sets, respectively, the current time, in seconds. ``` using Update = std::function<void(float t, float dt, bool final)>; using Render = std::function<void()>; Backend & update(Update const & update); Backend & render(Render const & render); ``` sets the `update` and `render` callbacks, respectively, used by ``` void run(float dt_max = 0.0F); ``` which is a convenience function that uses the member functions and callbacks described in this section to implement a render loop. `t` is the current time, which is set to `0.0F` at the start of `run`. If `dt_max` is `0.0F`, the `update` callback is called once for every frame, with `dt` holding the elapsed time. Otherwise, the `update` callback is called as many times as necessary to advance through the elapsed time while ensuring `dt` is never larger than `dt_max`. `final` is `true` if this is the final update of the frame. `render` is called at the end of each frame. Either of the callbacks can be unset. ### Input and output ``` void lock(bool lock); ``` controls mouse locking. If `true` is passed the mouse is locked, which means it is hidden and prevented from leaving the window. Passing `false` restores the normal behavior. The input (keyboard and mouse) and output (framebuffer) state can be accessed in two different ways: registering callbacks and / or polling. The same function name is used for both methods (with function overloading). These are described below. #### Keyboard The ``` key ``` *callback / poll* takes as argument a `std::string const & key` and *is called when / returns `true` if* that key is pressed. Valid arguments are backend-specific but guaranteed to support: - `"A"` through `"Z"` - `"0"` through `"9"` - `"Left"`, `"Right"`, `"Up"`, `"Down"` - `"Enter"`, `"Escape"`, `"Tab"`, `"Backspace"` - `"Control"`, `"Shift"`, `"Alt"` #### Mouse The ``` button ``` *callback / poll* takes as argument an `int button` and *is called when / returns `true` if* that button is pressed. Valid arguments are backend-specific but guaranteed to support `1`, `2`, and `3`. The ``` scroll ``` *callback / poll* takes as *argument / returns* `std::array<float, 2> scroll`. The ``` position ``` *callback / poll* takes as *argument / returns* `std::array<float, 2> position`. The ``` move ``` *callback / poll* takes as *argument / returns* `std::array<float, 2> move`. #### Framebuffer The ``` size ``` *callback / poll* takes as *argument / returns* `std::array<int, 2> size`. ### Persisting frames There is basic support for writing frames to disk, useful for testing or screenshot functionality. Writing is done with ``` bool frame_tga_write( std::string const & path ) const; ``` As the name suggests, the frame is written as an uncompressed [BGRA][] [Truevision TGA][] image, selected because it is widely supported and has a trivial header and data layout. The function returns `true` on success, on failure an [error](#errors) is emitted and `false` is returned. ``` bool frame_tga_compare( std::string const & path, bool write_on_failed_read = false ) const; ``` can be used to compare the current frame to one written previously. Note that a general TGA reader is not used; the comparison is done byte for byte, header included. If the given `path` cannot be read an [error](#errors) is emitted and if `write_on_failed_read` is `true` the current frame is instead written to `path`. `".tga"` is automatically added to the end of `path`. In addition, `directory` is applied if appropriate, see [File system](#file-system). No function is provided to read the frame without interacting with the file system. If this is required, simply use [`glReadPixels`][]. [BGRA]: https://en.wikipedia.org/wiki/RGBA_color_model [Truevision TGA]: https://en.wikipedia.org/wiki/Truevision_TGA [`glReadPixels`]: https://www.khronos.org/registry/OpenGL-Refpages/gl4/html/glReadPixels.xhtml ## Dependencies System dependencies that need to be installed: - Public (interface): - [OpenGL][] (e.g. [`libgl1-mesa-dev`][]). - [OpenGL Extension Wrangler (GLEW)][] (e.g. [`libglew-dev`][]). - Private (tests): - [GLFW][] (e.g. [`libglfw3-dev`][]). - [SDL2][] (e.g. [`libsdl2-dev`][]). - [wxWidgets][] (e.g. [`libwxgtk3.0-gtk3-dev`]). [OpenGL Extension Wrangler (GLEW)]: http://glew.sourceforge.net [`libgl1-mesa-dev`]: https://packages.debian.org/search?keywords=libgl1-mesa-dev [`libglew-dev`]: https://packages.debian.org/search?keywords=libglew-dev [`libglfw3-dev`]: https://packages.debian.org/search?keywords=libglfw3-dev [`libsdl2-dev`]: https://packages.debian.org/search?keywords=libsdl2-dev [`libwxgtk3.0-gtk3-dev`]: https://packages.debian.org/search?keywords=libwxgtk3.0-gtk3-dev ## Build system This project supports [CMake][] and uses [`cmake-common`][]. There are several ways to use it in other CMake-based projects: - With [`find_package`][]: ([Package][] and) [install][] it on the system. - With [`add_subdirectory`][]: Bundle it. - With [`FetchContent`][]: Download it as part of the CMake configure step. - With [`cmake-common`][]: Use any of the above methods through a simplified interface. As usual, use [`add_dependencies`][] or [`target_link_libraries`][] (or `cmake-common`'s `DEPENDENCIES_*`) to declare the dependency. [CMake]: https://cmake.org [`cmake-common`]: https://git.rcrnstn.net/rcrnstn/cmake-common [`FetchContent`]: https://cmake.org/cmake/help/v3.14/module/FetchContent.html [`add_subdirectory`]: https://cmake.org/cmake/help/v3.14/command/add_subdirectory.html [`find_package`]: https://cmake.org/cmake/help/v3.14/command/find_package.html [Package]: #Package [Install]: #Install [`add_dependencies`]: https://cmake.org/cmake/help/v3.14/command/add_dependencies.html [`target_link_libraries`]: https://cmake.org/cmake/help/v3.14/command/target_link_libraries.html ### Configure and generate To configure and generate a build tree, use `cmake`: ```sh cmake -B _build ``` To set the build type, pass e.g. `-D`[`CMAKE_BUILD_TYPE`][]`=Release`. [`cmake`]: https://cmake.org/cmake/help/v3.14/manual/cmake.1.html#generate-a-project-buildsystem [`CMAKE_BUILD_TYPE`]: https://cmake.org/cmake/help/v3.14/variable/CMAKE_BUILD_TYPE.html ### Build To build, use [`cmake --build`][]: ```sh cmake --build _build ``` To disable building tests, pass `-D`[`BUILD_TESTING`][]`=OFF`. [`cmake --build`]: https://cmake.org/cmake/help/v3.14/manual/cmake.1.html#build-a-project [`BUILD_TESTING`]: https://cmake.org/cmake/help/v3.14/module/CTest.html ### Test To run tests, use [`ctest`][]: ```sh (cd _build && ctest) ``` To show output from failing tests, pass `--output-on-failure`. To show output from all tests, pass `--verbose`. [`ctest`]: https://cmake.org/cmake/help/v3.14/manual/ctest.1.html ### Package To package, use [`cpack`][]: ```sh (cd _build && cpack) ``` [`cpack`]: https://cmake.org/cmake/help/v3.14/manual/cpack.1.html ### Install To install onto the current system, use [`cmake --install`][]: ```sh cmake --install _build ``` To set the prefix, pass e.g. `-D`[`CMAKE_INSTALL_PREFIX`][]`="$HOME/.local"`. [`cmake --install`]: https://cmake.org/cmake/help/v3.14/manual/cmake.1.html#install-a-project [`CMAKE_INSTALL_PREFIX`]: https://cmake.org/cmake/help/v3.14/variable/CMAKE_INSTALL_PREFIX.html ## License Licensed under the [ISC License][] unless otherwise noted, see the [`LICENSE`][] file. [ISC License]: https://choosealicense.com/licenses/isc [`LICENSE`]: LICENSE