558 lines
21 KiB
Markdown
558 lines
21 KiB
Markdown
# `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 need
|
|
* `engine`: contains the highest level of objects used for the engine
|
|
* `ext`: any abstraction that implements an external library
|
|
* `spec`: 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 under `uf::{namespace}`
|
|
* `uf`: contains complex classes whose underlying members are not safe to directly interact with; contains their own member functions
|
|
* `ext`: 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](https://github.com/nothings/stb)'s `stb_image`.
|
|
|
|
#### `engine/utils/image/atlas`
|
|
|
|
This provides the `uf::Atlas` class for storing images into an atlas, using [InfinityTools/binpack2d](https://github.com/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>`
|
|
* `pod::Quaternion<>`
|
|
* `pod::Matrix<>`
|
|
* example: `pod::Matrix4f`
|
|
* `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 initialization
|
|
* `tick`: called when the engine ticks
|
|
* `render`: called when a render mode ticks for rendering
|
|
* `destroy`: 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 the `uf::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 buffers
|
|
* `vorbis`: processes audio from an `.ogg` file through `libvorbis` (or `libtremor`) into buffers
|
|
* `wav`: processes audio from a `.wav` file through `dr_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](https://github.com/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](https://github.com/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](https://github.com/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](https://github.com/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](https://github.com/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](https://github.com/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](https://github.com/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/](https://github.com/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](https://github.com/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). |