21 KiB
engine/
This section of the project handles all the systems and structs needed for the engine.
This is further divided into four parts:
utils
: lower level systems and structs that the engine may needengine
: contains the highest level of objects used for the engineext
: any abstraction that implements an external libraryspec
: any abstraction that requires specialization / platform-specific code
Confusingly, these namespaces are exposed:
pod
: (mostly) contains plain-old-data structs, as they're safe to directly interact with its members, and get operated on through functions underuf::{namespace}
uf
: contains complex classes whose underlying members are not safe to directly interact with; contains their own member functionsext
: contains code that directly interacts with external libraries; typically shouldn't be directly invoked
This documentation is barebones as actual more examples and detailing of the functions provided are required, rather than just the classes and namespaces exposed. However, some examples are provided.
engine/utils/
engine/utils/audio/
This provides the uf::Audio
, uf::AudioEmitter
and uf::MappedAudioEmitter
classes.
engine/utils/camera/
This provides the uf::Camera
class.
engine/utils/component/
This provides the uf::Component
system, allowing an entity to own pod::Component<T>
s.
A uf::Component
maps a pod::Component<T>
by its underlying userdata typing.
.hasComponent<T>()
can be used to check if an entity has a component.
By default, .getComponent<T>()
will automatically invoke .addComponent<T>()
if that component isn't already added.
Example:
auto& transform = this->getComponent<pod::Transform<>>();
auto& camera = this->getComponent<uf::Camera>();
// only do something if there's already a physics state
if ( this->hasComponent<pod::PhysicsState>() ) {
auto& physics = this->getComponent<pod::PhysicsState>();
// ...
}
engine/utils/hook/
This provides the uf::hooks
system, allowing data and events to dispatch across the engine to anyone listening to the hook name and payload type.
Confusingly, this is a singleton and not a namespace to allow for separate hook pools to be utilized, although this usecase is currently not used.
While it's not usually used this way, return types from a hook are collected into a uf::stl::vector<uf::Userdata>
returned by uf::hooks.callHook
.
Arguments passed by non-const
reference can mutate along for other hooks to see.
Examples:
// add a hook
uf::hooks.addHook( "llm:VALL-E.synthesize", [&](ext::json::Value& json){
auto text = json["text"].as<uf::stl::string>();
auto prom = json["prom"].as<uf::stl::string>();
auto play = json["play"].as<bool>();
auto callback = json["callback"].as<uf::stl::string>("");
uf::thread::queue( uf::thread::asyncThreadName, [=](){
auto waveform = ext::vall_e::generate( text, prom );
if ( callback != "" ) {
uf::hooks.call( callback, waveform );
} else if ( play ) {
uf::Audio audio;
audio.load( waveform );
audio.play();
}
});
});
// dispatch via JSON
ext::json::Value payload;
payload["text"] = "The birch canoe slid on the smooth planks.";
payload["prom"] = "./data/tmp/prom.wav";
payload["play"] = true;
uf::hooks.call( "llm:VALL-E.synthesize", payload );
// or through a payload struct
struct TTSPayload {
uf::stl::string text;
uf::stl::string prom;
};
uf::hooks.addHook( "llm:VALL-E.synthesize", [&]( TTSPayload& payload ){
return ext::vall_e::generate( payload.text, payload.prom );
});
auto waveform = uf::hooks.callHook("llm:VALL-E.synthesize", {
"The birch canoe slid on the smooth planks.", "./data/tmp/prom.wav"
})[0];
engine/utils/http/
This provides the uf::http
system through cURL.
Currently, only uf::http::get
is provided for GET
ting resources.
engine/utils/image/
This provides the uf::Image
class for storing image data.
Images are loaded as RGBA8
buffers using nothings/stb's stb_image
.
engine/utils/image/atlas
This provides the uf::Atlas
class for storing images into an atlas, using InfinityTools/binpack2d as the packer.
engine/utils/io/
This folder provies:
uf::console
uf::io
uf::inputs
uf::IoStream
engine/utils/math/
This folder provides:
pod::Vector<>
- examples:
pod::Vector3f
,pod::Vector4f
,pod::Vector2ui
,pod::Vector<6, char>
- examples:
pod::Quaternion<>
pod::Matrix<>
- example:
pod::Matrix4f
- example:
pod::Transform<>
uf::quant
uf::physics
- unused collision detection
- and other things
To-do: document the uf::vector
, uf::quaternion
, uf::matrix
, uf::transform
namespaces
engine/utils/memory/
This folder provides wrappers for STL containers to optionally integrate with the internal memory pools:
uf::stl::vector
uf::stl::unordered_map
uf::stl::fifo_map
uf::stl::KeyMap
uf::stl::deque
uf::stl::stack
uf::stl::queue
uf::stl::map
And the memory pool through uf::memoryPool
.
engine/utils/mesh/
This contains
- a struct for attribute descriptors
- vertex descriptors for meshes
- structs for draw commands, instances, and primitives
- a generic class
uf::Mesh
for inserting and binding vertex data for rendering
engine/mesh/grid
This contains uf::meshgrid
for slicing a mesh into grids.
This is primarily only used within engine/ext/gltf/gltf.cpp
for partitioning existing models before saving to the engine's internal format.
This can be invoked outside of this context, but currently does is not used beyond the above use-case.
engine/utils/noise/
This provides noising functions, such as perlin noise through uf::PerlinNoise
.
However, this implementation is quite cringe as it's from 2013 or 2014.
engine/utils/resolveable/
This provides a wrapper class pod::Resolveable<T>
that either returns its ID or its pointer type. This is seldomly used for handling entity information, where it can be defined by its UID or pointer directly.
engine/utils/serialize/
This provides uf::Serializer
, a wrapper around ext::json::Value
to read from / write to disk.
For the most part, this is used interchangeably with ext::json::Value
.
engine/utils/singletons/
This provides uf::StaticInitialization
, a cringe way to implement pre-main()
static initialization through singletons.
This is primarily used for registering component enums through Lua.
engine/utils/string/
This provides a myriad of string functions through uf::string
.
engine/utils/text/
This provides uf::Glyph
, a wrapper around FreeType2
for holding glyph information.
This shouldn't directly be interfaced with, as the GUI system handles this.
engine/utils/thread/
This provides uf::thread
system for multithreading.
For the most part, this should only be interfaced per the example:
// something asynchronously
uf::thread::queue( uf::thread::asyncThreadName, [=](){
// ...
});
// something via a worker thread
uf::thread::queue( uf::thread::fetchWorker(), [=](){
// ...
});
auto tasks = uf::thread::schedule(true); // true to multithread, false to not
tasks.queue([&](){
// ...
})
uf::thread::execute( tasks );
engine/utils/time/
This provides uf::Timer<>
and uf::time
, time and timer related functions.
For the most part, timers are used via a macro, and deltaTime is grabbed through uf::physics::time::delta
.
engine/utils/userdata/
This provides uf::userdata
and uf::pointeredUserdata
(to-do: alias the latter into the former), where pod::Userdata
(and the uf::Userdata
wrapper) contains arbitrary userdata identified by its size and type.
For the most part, this shouldn't directly be interfaced, as this is used for other systems to operate, but an example:
someMap[k] = uf::userdata::create<uf::Camera>();
// ...
auto& v = uf::userdata::get<T>( someMap[key] );
// ...
if ( someMap[k] ) uf::userdata::destroy( someMap[k] );
engine/engine/
engine/engine/asset/
This implements the uf::asset
system which governs asset loading.
Assets can be cached for subsequent loads.
When an asset is loaded, it's dispatched through the hook system by invoking the hook name specified as its callback (usually asset:Load.%UID%
).
This shouldn't be directly invoked, rather utilized through an entity's JSON configuration or existing hooks (usually asset:QueueLoad.%UID%
).
Assets can implicitly resolve absolutely based on the extension per uf::io::resolveURI
.
engine/engine/behavior/
This implements the pod::Behavior
struct and uf::Behaviors
system.
pod::Behavior
stores function pointers for the primary entity functions:
initialize
: called on entity initializationtick
: called when the engine ticksrender
: called when a render mode ticks for renderingdestroy
: called when the entity is to be destroyed
uf::Behaviors
is a class for instantiation to handle an entity's list of behaviors. A graph is generated that flattens a scene graph tree for subsequent use.
This should never be directly interfaced with. Macros handle everything required, and reference to these macros can be found in any behavior.cpp
and behavior.h
pairs.
engine/engine/entity/
This implements uf::Entity
and uf::EntityBehavior
, the core for an entity in this engine.
uf::Entity
should handle the lowest level functions needed, such as UID and name, its parent and children, and containing its components and behaviors.
engine/engine/graph/
This system implements everything for rendering objects in a scene.
A pod::Graph
contains all the information needed to render a scene, from its textures and material information, to meshes, instance information, animations, to draw calls and how additional entities are to be loaded.
Anything non-GUI entity is expected to be registered through here. Having said that, the object system should handle the gorey details of passing an entity through here.
Additional functions:
uf::graph::convert
handles "importing" a naive entity scene graph into theuf::graph
graph system.uf::graph::load
handles loading, from disk, a pre-processed scene graph into the engine.uf::graph::save
handles saving, to disk, a scene graph to disk.
engine/engine/instantiator/
This implements the uf::instantiator
system, which governs instantiating entities as objects against a given list of object names and behavior names.
This system is responsible for binding behaviors to a named entity type, but use of this feature seems to have been removed in favor of another implementation.
For the most part, this does handle allocation and garbage collection of entities.
engine/engine/object/
This implements uf::Object
and uf::ObjectBehavior
, where an object extends upon an entity by implementing additional features, such as:
- instantiating the object and initializing components per the configuration JSON
- pre-defined cleanup behaviors for given components
- resolving relative pathnames and relative hook names
- asset loading
- processing hooks (adding, calling, queueing)
- reloading from the JSON when its updated
If UF_ENTITY_OBJECT_UNIFIED
is set, then an entity and an object are truly interchangeable, but for the most part one can be casted to the other.
engine/engine/scene/
This implements uf::Scene
and uf::SceneBehavior
structs and the uf::scene
system.
A scene contains all of its entities, and orchestrates the scene graph. A scene is responsible for finding a controller (and thus camera) for a given render mode,
A scene's JSON is defined under ./data/scene/{name}/
and can be directly loaded on startup under ./data/config.json
's engine.scene.start
value.
While it's not utilized, additional scenes can be loaded onto the stack, or unloaded to "go back" to the prior scene.
engine/ext/
engine/ext/audio/
This abstracts audio codecs for use under OpenAL.
Currently implemented:
pcm
: processes raw PCM audio into buffersvorbis
: processes audio from an.ogg
file throughlibvorbis
(orlibtremor
) into bufferswav
: processes audio from a.wav
file throughdr_wav
into buffers
Audio is first read for its metadata, then either fully loaded into one buffer, or streamed into smaller buffers.
Enabled through their respective compile feature flag, and flagged through their respective UF_USE_{NAME}
flags.
engine/ext/discord/
This abstracts around the Discord library for activity integration.
For the most part this is left uncompiled as it was just a loose gimmick by dispatching through the discord:Activity.Update
hook.
Enabled through the discord
compile feature flag, and flagged through UF_USE_DISCORD
.
engine/ext/ffx/
This abstracts around AMD's FSR2 library.
This is semi-unused as I need to update it to FSR3, and it's a bit of a sloppy implementation, given how much pain was needed to get it to compile under GCC and how poor the documentation was.
Enabled through the ffx:fsr
compile feature flag, and flagged through UF_USE_FFX_FSR
.
engine/ext/freetype/
This abstracts around FreeType2 for creating bitmaps for a given font file, as well as provide metrics for a given glyph.
Enabled through the freetype
compile feature flag, and flagged through UF_USE_FREETYPE
.
engine/ext/gltf/
This abstracts around the GTLf file specification through tiny_gltf
.
For the most part, this handles loading a .gltf
(or .glb
) and processes it through the engine's uf::graph
system, from which it can be saved to disk using its own internal format.
Enabled through the gltf
compile feature flag, and flagged through UF_USE_GLTF
.
engine/ext/imgui/
This abstracts around the Dear ImGui
library for a more-in-depth GUI system.
For the most part, this only (poorly) implements a console window.
Enabled through the imgui
compile feature flag, and flagged through UF_USE_IMGUI
.
engine/ext/json/
This abstracts around nlohmann/json to provide an ext::json::Value
object and ext::json
namespace for operating on JSON objects.
Enabled through the json:nlohmann
compile feature flag, and flagged through UF_JSON_USE_NLOHMANN
.
- it is highly recommended to enable this.
engine/ext/lua/
This abstracts around Lua through ThePhD/sol2 to extend the engine through Lua scripts.
Usertypes are provided under engine/ext/lua/usertypes
:
uf::Asset
uf::Audio
uf::Camera
pod::Matrix4f
uf::Object
pod::Physics
pod::Quaternion<>
uf::Timer<>
pod::Transform<>
pod::Vector<>
On load, ./data/scripts/main.lua
is called, although nothing is directly in there yet.
Additional library tables are provided that map to internal engine functions through:
hooks.add
:uf::hooks::addHook
hooks.call
:uf::hooks::callHook
entities.get
entities.currentScene
:uf::scene::getCurrentScene
entities.controller
:uf::scene::getCurrentScene().getController
entities.destroy
:self:queueDeletion
string.extension
:uf::string::extension
string.resolveURI
:uf::string::resolveURI
string.si
:uf::string::si
string.match
:uf::string::match
string.matched
:uf::string::matched
io.print
math.clamp
:math::clamp
time.current
:uf::physics::time::current
time.previous
:uf::physics::time::previous
time.delta
:uf::physics::time::delta
json.pretty
:uf::Serializer::serialize
json.readFromFile
:uf::Serializer::readFromFile
json.writeToFile
:uf::Serializer::writeToFile
window.keyPressed
:uf::Window::isKeyPressed
os.arch
:UF_ENV
inputs.key
:uf::inputs::key
inputs.analog
:uf::inputs::analog
inputs.analog2
:uf::inputs::analog2
Enabled through the lua
compile feature flag, and flagged through UF_USE_LUA
.
engine/ext/meshopt/
This abstracts around zeux/meshoptimizer to optimize meshes.
For the most part, this is automatically called when loading from a gLTF file.
The ext::meshopt
namespace is provided if needed.
Enabled through the meshopt
compile feature flag, and flagged through UF_USE_MESHOPT
.
engine/ext/oal/
This abstracts around OpenAL for the audio system through ext::al
.
Most OpenAL parameters are handled. This shouldn't directly be invoked, as it's handled through uf::Audio
Enabled through the openal
compile feature flag, and flagged through UF_USE_OPENAL
.
engine/ext/opengl/
This abstracts around OpenGL to provide the rendering system.
Most of this is enough to allow the engine to render using OpenGL 1.2.
A hand-crafted command buffer system is provided through engine/ext/opengl/commands.cpp
to keep it seamlessly integrated with the engine that was primarily Vulkan-integrated.
Enabled through the opengl
compile feature flag, and flagged through UF_USE_OPENGL
.
engine/ext/openvr/
This abstracts around ValveSoftware/openvr to provide VR support.
Support needs to be repaired as the rendering system was modified heavily after adding VR support.
Enabled through the openvr
compile feature flag, and flagged through UF_USE_OPENVR
.
engine/ext/reactphysics/
This abstracts around DanielChappuis/reactphysics3d to provide a physics system through uf::physics
.
Confusingly, this aliases to uf::physics::impl
.
Enabled through the reactphysics
compile feature flag, and flagged through UF_USE_REACTPHYSICS
.
engine/ext/toml/
This abstracts around marzer/tomlplusplus to provide TOML support.
For the most part, this is left unused and just wraps around to ext::json::Value
, as it was explored as an alternative to JSON for reading configuration data.
Enabled through the toml
compile feature flag, and flagged through UF_USE_TOML
.
engine/ext/ultralight/
This abstracts around ultralight-ux/Ultralight to provide rendering websites.
For the most part, this is left unused as it was a one-off gimmick in lieu of using something like Awesomium (or Chromium).
Enabled through the ultralight-ux
compile feature flag, and flagged through UF_USE_ULTRALIGHT_UX
.
engine/ext/vall_e/
This abstracts around e-c-k-e-r/vall-e/ to provide TTS support.
For the most part, this is added to provide an example on how to integrate a C++ project, and to justify burning two years on this meme.
Enabled through the vall_e
compile feature flag, and flagged through UF_USE_VALL_E
.
engine/ext/vulkan/
This abstracts around Vulkan to provide the rendering system.
There's a ton of stuff it exposes that should necessitate its own documentation.
Enabled through the vulkan
compile feature flag, and flagged through UF_USE_VULKAN
.
engine/ext/xatlas/
This abstracts around jpcy/xatlas to provide UV unwrapping used for lightmap baking.
Enabled through the xatlas
compile feature flag, and flagged through UF_USE_XATLAS
.
engine/ext/zlib/
This abstracts around zlib
to provide compression and decompression of .gz
files.
Enabled through the zlib
compile feature flag, and flagged through UF_USE_ZLIB
.
engine/spec/
engine/spec/context/
This handles per-platform OpenGL context code.
engine/spec/controller/
This handles per-platform code for handling controllers.
For now, only the Dreacmast has code for its controllers. Controller support via OpenVR was handled, but it lives in its own code.
engine/spec/renderer/
This provides an alias to which rendering backend to utilize.
engine/spec/terminal/
This handles per-platform code for configuring the terminal window the program loads under.
For the most part, this was used for engine/utils/io/iostream
with locale black magic and Ncurses, but Ncurses has been dropped for a while now.
engine/spec/time/
This handles per-platform code for getting time information.
For the most part, this is quasi-necessary for the Dreamcast to get a timestamp for timing, but I'm pretty sure the universal approach can work too.
engine/spec/window/
This handles per-platform code for providing a window to run the program within.
Windows is mainly supported through win32
black magic, but Dreamcast-specific code lives within here as well (despite there not being a windowing system).