Libdonut is an application framework for cross-platform game development in C++20.
- Template project with some instructional comments: template/src/main.cpp
- Single-file test game using various features: examples/example_game.cpp
- Basic application that renders a rectangle: examples/example_rectangle.cpp
- Application framework:
- Application base class:
- Defines the main loop of the program in a platform-agnostic way that supports both native Windows/Linux compilation as well as the emscripten WebAssembly runtime.
- Includes an optional built-in frame rate limiter.
- Provides both per-frame update callbacks and frame rate-independent pacing of fixed-rate tick updates.
- Application base class:
- Events system:
- EventPump:
- Polls Event data from the environment on demand.
- InputManager:
- Maps physical Input events to abstract action numbers.
- Supports simultaneous keyboard, mouse, touch and controller input.
- EventPump:
- Audio engine using SoLoud:
- Sound loading:
- Supports OGG, WAV, FLAC and MP3 formats.
- SoundStage:
- Plays 3D positional audio, background sounds and music.
- Sound loading:
- Graphics rendering through OpenGL:
- Window abstraction:
- Handles GL context setup and window management using SDL.
- Renderer:
- RenderPass interface for simple batch rendering:
- 3D Model rendering that supports custom shaders through Shader3D or basic built-in Blinn-Phong lighting for prototyping.
- 2D Textured quad rendering with built-in shaders or custom shaders through Shader2D.
- Sprite rendering with automatic SpriteAtlas packing.
- Text rendering and Font loading using libschrift.
- Supports arbitrary Framebuffer targets, Camera positions and Viewport areas.
- Viewports can be restricted to integer scaling for pixel-perfect fixed-resolution 2D rendering regardless of window size.
- RenderPass interface for simple batch rendering:
- Model loading from OBJ files.
- Image loading/saving using stbi.
- Window abstraction:
- Utilities:
- Hand-written parsers and writers for some common data formats:
- JSON:
- Serialize/deserialize arbitrary types to/from JSON.
- Write/read JSON data to/from both strings and iostreams.
- Supports memory-efficient visitor-based parsing.
- Supports JSON5 features (comments, trailing commas, identifier keys, etc.).
- OBJ:
- Parse OBJ models and basic MTL materials.
- XML:
- Parse XML documents into a simple tree structure in memory.
- Base64
- Encode/decode aribtrary data to/from standard Base64 strings.
- Unicode:
- Iterate the Unicode code points of UTF-8-encoded text in any sequence of bytes with simple error reporting in case of invalid encoding.
- JSON:
- AtlasPacker for packing rectangles into expandable square texture atlases.
- Floating-point RGBA Color type that includes predefined constants for common web colors.
- Virtual Filesystem based on PhysicsFS:
- Use virtual filepaths for uniform access to any resource File that resides in a mounted directory, regardless of its actual location.
- Supports automatic mounting of pk3/zip/etc. archives at startup for easy mod loading.
- Used for all built-in resource loading in libdonut.
- Custom Variant implementation:
- Enhances the API of std::variant by adding the methods
is<T>()
,as<T>()
,get<T>()
andget_if<T>()
as well as a freestandingmatch
function. - Visitation is implemented through chaining of the conditional operator rather than virtual method dispatch, making it easier for compilers to generate a jump table than in most common std::variant implementations. This puts
match
on par with a raw switch statement in terms of performance. - Supports being used as a base class in user code.
- Enhances the API of std::variant by adding the methods
- Loose Quadtree container for accelerating AABB collision tests between a large number of objects in 2D.
- Time duration wrapper including common utility functions for correctly handling discrete-time update loops.
- Fast pseudo-random number generation engine using xoroshiro128++:
- Designed to be used as a URBG in conjunction with the standard C++ distributions.
- Compile-time reflection of aggregate types through some dark template magic.
- Supports iterating references to the fields of an instance of any plain struct, with full type information available.
- Used in libdonut to automate JSON serialization, vertex attribute setup, etc.
- Basic geometric shapes with intersection tests.
- Hand-written parsers and writers for some common data formats:
- Donut the Vikingchap: https://steamcommunity.com/id/donutvikingchap/
The API reference for the latest version of libdonut is available here: https://donutvikingchap.github.io/libdonut/index.html
The following programs need to be installed in order to build an application using libdonut:
- CMake (version 3.21+).
- A C++20-compatible compiler, such as:
Follow these steps to create a new application project using libdonut:
- Copy the contents of the included template/ directory into a newly created folder for your project.
- Edit the
CMakeLists.txt
file in your new project folder as follows:- Change the project name at the top of the file.
- Optional, but recommended: Set the GIT_TAG to the commit hash of the libdonut release that you want to use instead of
"origin/main"
. - Optional: Change the value of APP_TARGET_NAME from
"app"
to your desired application executable name.
- Use CMake to configure the project. This can be done by running the following commands from within your new project folder:
CMake will then use FetchContent to automatically download a copy of libdonut and all of the required dependencies, and save them under
mkdir build cd build cmake ..
build/_deps/
.
After performing the configuration steps described above, the project can be built from the build/
folder at any time using the following command to compile in debug mode:
cmake --build . --config Debug
or the following command to compile in performance-optimized release mode instead:
cmake --build . --config Release
The resulting application executable is written to build/bin/
.
When adding new source files to your project, make sure to also add their filepaths to the add_executable
command in CMakeLists.txt
, before or after "src/main.cpp"
, and reconfigure CMake with the cmake ..
command. Otherwise, the new files will not be included in the build.
When running the compiled executable, make sure that the current working directory is set to point to the folder where your main data directory is located, if you have one. Otherwise, your application will likely fail to run due to missing resources.
If you have Doxygen installed, you can build a local copy of the API reference for libdonut as follows.
After configuring your new project, run the following command from inside the build/
directory to generate the documentation for libdonut's API:
cmake --build . --target donut-generate-documentation
The generated HTML file at build/_deps/donut-build/docs/html/index.html
can then be opened in your favorite web browser to read the documentation and navigate it like a website.
After compiling your project in release mode, the resulting application executable can be packaged into a folder along with its main data directory and be distributed according to the relevant licenses mentioned below. A sample copyright.txt
file is provided in the project template to illustrate the copyright notices that must be included when distributing an application containing the code of libdonut and its direct dependencies. Note that this is only an example and not any form of legal advice.
Libdonut is distributed under the MIT License. See the included LICENSE file for more information.
Libdonut depends on the C++ standard library, for which any C++20-compatible implementation may be used, as well as the following third-party libraries, each one having its own license, with some including further dependencies:
- {fmt} (MIT License)
- glad (glad/gl.h is Public Domain, khrplatform.h is under MIT License)
- GLM (MIT License)
- libschrift (ISC License)
- PhysicsFS (zlib License)
- SDL (zlib License)
- SoLoud (zlib License)
- stb (Public Domain)
For graphics, libdonut expects the end user to have an available graphics driver installed that implements the OpenGL Graphics System (Version 3.3 (Core Profile)) specification. The graphics library is loaded at runtime through glad, using the function loader provided by SDL.