VoidEngine exposes a reusable C++20 static library named VoidEngine. The main convenience include is:
#include <void_engine/engine.h>That header includes the public engine surface from core, platform, renderer, scene, ui, and editor.
Inside this repository, CMake targets link directly against VoidEngine:
target_link_libraries(MyApp PRIVATE VoidEngine)The editor, demo, tools, and tests all use the same engine library target.
ve::Application owns the main engine subsystems and drives the game loop.
Owned systems include:
- window and OpenGL context
- time and fixed physics tick
- input and gamepad manager
- event bus
- job system
- audio device
- ImGui layer
- splash screen
Typical usage:
#include <void_engine/engine.h>
class MyApp final : public ve::Application {
public:
MyApp()
: ve::Application(makeConfig()) {}
protected:
void onInit() override {
m_device.init();
m_scene.initPhysics();
}
void onPhysicsUpdate(ve::f64 fixedDt) override {
m_scene.stepPhysics(static_cast<ve::f32>(fixedDt));
}
void onUpdate(ve::f64 dt) override {
m_scene.stepAnimations(static_cast<ve::f32>(dt));
m_scene.stepParticles(static_cast<ve::f32>(dt));
m_scene.stepScripts(static_cast<ve::f32>(dt), &getInput());
}
void onRender() override {
m_device.clear();
m_scene.render(m_camera, m_device);
}
private:
static ve::AppConfig makeConfig() {
ve::AppConfig config;
config.window.title = "My VoidEngine App";
config.window.width = 1600;
config.window.height = 900;
return config;
}
ve::Scene m_scene;
ve::RenderDevice m_device;
ve::FreeCamera m_camera;
};
int main() {
MyApp app;
app.run();
}| Header | Purpose |
|---|---|
core/application.h |
Main application base class and subsystem ownership. |
core/log.h |
Engine logging and log entries consumed by the editor console. |
core/event_bus.h |
Event dispatch infrastructure. |
core/time.h |
Frame timing and fixed physics tick support. |
core/input.h |
Keyboard, mouse, and input state. |
core/input_map.h |
Named actions mapped to keyboard, mouse, and gamepad bindings. |
core/gamepad.h |
GLFW gamepad access. |
core/job_system.h |
Parallel job execution for engine-scale work. |
core/audio_* |
Audio device, clips, sources, mixer, music streams, and playlists. |
core/physics_world.h |
Jolt-backed physics world, bodies, queries, and stepping. |
core/asset_baker.h |
Mesh/texture baking helpers used by vebake. |
core/asset_pack.h |
.vepack writer/reader helpers used by vepack. |
core/game_package.h |
.vegame.json runtime package metadata. |
ve::Scene is the central runtime/editor container. It owns:
- entity pool
- UUID mapping
- generic component stores
- transform hierarchy
- rendering integration
- physics integration
- script runtime state
- animation and particle stepping
- serialization snapshots for play mode
Basic entity/component flow:
ve::Scene scene;
ve::Entity entity = scene.createEntity();
scene.addName(entity, "Player");
auto& transform = scene.addTransform(entity);
transform.position = {0.0f, 1.0f, 0.0f};
scene.addRigidbody(entity, {.motionType = ve::PhysicsMotionType::Dynamic});
scene.addCollider(entity, ve::ColliderComponent::makeBox({0.5f, 0.5f, 0.5f}));Generic component API:
scene.addComponent<MyComponent>(entity, MyComponent{});
if (scene.hasComponent<MyComponent>(entity)) {
auto& component = scene.getComponent<MyComponent>(entity);
}
scene.removeComponent<MyComponent>(entity);Multi-component queries:
scene.each<ve::TransformComponent, ve::MeshRendererComponent>(
[](ve::Entity entity, auto& transform, auto& meshRenderer) {
// Process renderable entity.
});Parallel query:
scene.parallelEach<ve::TransformComponent, ve::AnimatorComponent>(
jobs,
[](ve::Entity entity, auto& transform, auto& animator) {
// Process animation-related data.
});| Component | Purpose |
|---|---|
TransformComponent |
Local transform and parent-child relationship. |
NameComponent |
Human-readable entity display name. |
MeshRendererComponent |
Mesh and material reference for rendering. |
LightComponent |
Directional, point, and spot lighting data. |
RigidbodyComponent |
Physics body settings. |
ColliderComponent |
Box, sphere, capsule, and collision shape data. |
TriggerComponent |
Trigger/overlap behavior. |
ScriptComponent |
Lua script path and runtime script hooks. |
AnimatorComponent |
Skeletal animation state. |
ParticleEmitterComponent |
Runtime particle emitter configuration. |
TerrainComponent |
Terrain heightfield, splat layers, foliage, and terrain rendering data. |
PrefabInstanceComponent |
Prefab linkage and revert/detach workflow support. |
Important renderer types:
| Type | Purpose |
|---|---|
RenderDevice |
OpenGL render-state and draw wrapper. |
ShaderProgram |
Shader compilation, linking, uniforms, and hot reload support. |
ShaderLibrary |
Named shader collection. |
Mesh |
GPU mesh buffers with typed vertex layout support. |
Texture2D |
Texture loading, parameters, and GL ownership. |
CubemapTexture |
Skybox and image-based lighting cubemap support. |
Framebuffer |
Off-screen rendering target. |
Camera / FreeCamera |
Projection/view camera utilities. |
Font / UIRenderer |
Font loading and retained UI drawing support. |
ve::Scene::render(camera, device) can render entities with Transform + MeshRenderer and applies scene environment settings.
Scene rendering supports:
- forward rendering
- deferred rendering path
- directional/point/spot lighting
- shadow resources
- skybox
- image-based lighting
- SSAO
- bloom
- tone mapping
- gamma correction
- FXAA
- vignette
- color grading controls
- instancing/static batching
- frustum and occlusion culling infrastructure
- physics debug rendering
- particle and terrain rendering
Environment access:
auto& environment = scene.getEnvironment();
environment.ambient = {0.12f, 0.10f, 0.13f};
environment.lightDirection = {0.3f, -0.8f, 0.5f};
environment.lightIntensity = 1.2f;
auto& deferred = scene.getDeferredRendererSettings();
deferred.enabled = true;
deferred.bloom = true;
deferred.toneMapping = true;Physics is exposed through ve::PhysicsWorld and scene convenience APIs.
Common flow:
scene.initPhysics();
ve::Entity entity = scene.createEntity();
scene.addTransform(entity);
scene.addRigidbody(entity, {.motionType = ve::PhysicsMotionType::Dynamic});
scene.addCollider(entity, ve::ColliderComponent::makeBox({1.0f, 1.0f, 1.0f}));
scene.stepPhysics(fixedDeltaTime);Picking and raycasts:
ve::SceneRaycastHit hit;
bool found = scene.pickClosest(camera, mousePosition, viewportSize, hit);Trigger helpers:
std::vector<ve::Entity> overlaps = scene.getTriggerOverlaps(triggerEntity);
bool touching = scene.isTriggerOverlapping(triggerEntity, otherEntity);Lua scripts are attached through ScriptComponent. The scene owns script runtime state and exposes update/physics hooks.
ve::ScriptComponent script;
script.path = "samples/scripts/rotator.lua";
scene.addScript(entity, script);
scene.stepScripts(deltaTime, &input);
scene.stepScriptPhysics(fixedDeltaTime, &input);
scene.reloadScripts();The editor inspector can assign .lua files through drag-drop from the Asset Browser and includes a Reload Scripts button.
ve::InputMap maps named actions to keyboard, mouse, and gamepad bindings. It is used by game packages through controls JSON files.
Supported binding sources:
KeyboardMouseButtonGamepadButtonGamepadAxis
Runtime use:
ve::InputMap map;
map.loadFromFile("game/config/signal_breach.controls.json");
map.update(input, 0);
if (map.isActionPressed("fire")) {
// Fire once.
}
float moveRight = map.getActionValue("move_right");Audio APIs are split into:
AudioDeviceAudioClipAudioSourceAudioMixerMusicStreamMusicPlaylist
The implementation is designed for sound effects, grouped mixing, priorities, virtualization, streamed music, playlists, and crossfade-style flows.
| API | Purpose |
|---|---|
AssetBaker |
Convert mesh/texture data into runtime-friendly baked formats. |
AssetPackReader / packDirectory |
Read/write .vepack archives. |
ResourceManager |
Runtime resource ownership and lookup. |
TextureManager |
Texture cache and loading helper. |
AssetMetadata |
UUID/path metadata for assets. |
These APIs are also used by the CLI tools documented in Assets, Packages, and Tooling.
ve::SceneSerializer reads and writes scene JSON.
ve::SceneSerializer serializer(scene);
serializer.saveToFile("samples/scenes/my_scene.scene.json");
serializer.loadFromFile("samples/scenes/my_scene.scene.json");Mesh, material, and texture pointers are non-owning runtime references. Use SceneSerializer::AssetResolver to map runtime pointers to stable string IDs during save and back to pointers during load.
ve::GamePackage represents .vegame.json metadata.
Fields include:
- version
- title
- description
- scenario id
- startup scene
- controls config
- asset root
- optional asset pack
Use it to resolve package-relative paths:
ve::GamePackage package;
package.loadFromFile("game/signal_breach.vegame.json");
auto base = std::filesystem::path("game");
auto scenePath = package.resolveStartupScene(base);
auto controlsPath = package.resolveControlsConfig(base);The editor UI classes live in the engine library so they can be reused by the main editor app or future editor tools.
| Class | Purpose |
|---|---|
SceneHierarchyPanel |
Entity tree panel. |
InspectorPanel |
Component property editor. |
ViewportPanel |
Scene/Game viewport and gizmos. |
AssetBrowserPanel |
Filesystem asset browser. |
ConsolePanel |
Log viewer. |
ProfilerPanel |
Frame profiler UI. |
UndoHistory |
Undo/redo command stack. |
PlayModeManager |
Editor/play/paused state and scene snapshot restoration. |
For full usage details see Editor Guide.