README.md
1ed27b7e
 # [`glbackend`][]
 
 A [C++11][]/[OpenGL][] \>=[1.0][] [backend][] library.
 
8c34841f
 Currently supported backends (one from each category listed under
 [Context/Window Toolkits][] on the OpenGL wiki):
583abb86
 
8c34841f
 | 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` |
583abb86
 
1ed27b7e
 [`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
8c34841f
 [Context/Window Toolkits]: https://www.khronos.org/opengl/wiki/Related_toolkits_and_APIs#Context/Window_Toolkits
b3b5c285
 [GLFW]: https://www.glfw.org
aa70ce7e
 [SDL2]: https://www.libsdl.org
8c34841f
 [wxWidgets]: https://www.wxwidgets.org
 [Widget toolkit]: https://en.wikipedia.org/wiki/Widget_toolkit
e0c0a938
 
583abb86
 ## 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
 
17a267f2
 ## Dependencies
 
 System dependencies that need to be installed:
 
 -   Public (interface):
     -   [OpenGL][] (e.g. [`libgl1-mesa-dev`][]).
     -   [OpenGL Extension Wrangler (GLEW)][] (e.g. [`libglew-dev`][]).
b3b5c285
 -   Private (tests):
     -   [GLFW][] (e.g. [`libglfw3-dev`][]).
aa70ce7e
     -   [SDL2][] (e.g. [`libsdl2-dev`][]).
8c34841f
     -   [wxWidgets][] (e.g. [`libwxgtk3.0-gtk3-dev`]).
17a267f2
 
 [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
b3b5c285
 [`libglfw3-dev`]: https://packages.debian.org/search?keywords=libglfw3-dev
aa70ce7e
 [`libsdl2-dev`]: https://packages.debian.org/search?keywords=libsdl2-dev
8c34841f
 [`libwxgtk3.0-gtk3-dev`]: https://packages.debian.org/search?keywords=libwxgtk3.0-gtk3-dev
17a267f2
 
 ## 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
 
e0c0a938
 ## License
 
 Licensed under the [ISC License][] unless otherwise noted, see the
 [`LICENSE`][] file.
 
 [ISC License]: https://choosealicense.com/licenses/isc
 [`LICENSE`]: LICENSE