Track
Engines & Graphics
A Bevy-style ECS in C++20 where a system’s parameter list is its dependency declaration, and the scheduler proves at registration time that no two systems in a stage can conflict.
Three years moving up the abstraction ladder: calling the graphics API directly, then abstracting it behind a backend-agnostic interface, then designing the framework that other code plugs into.
2021
Solo · archived
My first engine: an OpenGL renderer with a skeletal animation importer, a templated ECS and an ImGui editor, later ported to Vulkan.
- Skeletal animation from glTF, written by hand: inverse bind matrices read straight from the accessor, joint parents reconstructed by walking node children, then animation channels and samplers decoded into per-joint translation, rotation and scale tracks keyed by time.
- A templated ECS where components live in a static ComponentContainer<T> and entities hold indices rather than pointers, with variadic CreateComponent<T>(args...) and a move-constructor specialization so components survive their vector being resized.
- An ImGui editor with a docked viewport, scene hierarchy, properties panel, console and file browser, about 1,000 lines of it.
- Single-file GLSL split per stage and compiled with shaderc, with a shader cache and reflection-driven material shaders.
- Ported from OpenGL to Vulkan on its own branch: instance, device, swapchain, render pass, pipeline, descriptor pool and buffer abstractions, about 2,100 lines.
- commits
- 125
- own source
- 6,091 LOC
- Vulkan layer
- 2,113 LOC
The link points at branch Vulkan, which is the final state. master stops in February 2022, before the port.
The animation system was lost, not finished: the February 2022 importer rewrite carried over everything except skinning, and only the Joint and Animation structs survive at the tip. It works in the December 2021 history.
2022
With a collaborator · archived
A C++20 game engine with a dockable editor.
Personal project. My father joined for part of it and wrote the original Vulkan boilerplate; I re-architected the renderer in 2023.
- SPIR-V reflection drives the material system: single-file GLSL is split per stage, compiled with shaderc, reflected with SPIRV-Cross into a recursive type tree and descriptor set layouts, vertex input and per-material uniform buffers are all generated from it.
- Native scripting uses a C++20 requires-expression to detect at compile time which event handlers a script defines, subscribing only to those; subscriptions are RAII handles that unsubscribe on destruction.
- The Bullet physics library gives you persistent manifolds, not callbacks. The collision layer walks the manifolds, maps user pointers back to entities, and produces Enter/Stay/Exit events from a per-body tracker.
- Entering play mode deep-copies the scene in two passes with an equivalence map, so cross-entity references such as physics constraints are fixed up correctly and edits revert on stop.
- The engine has no ImGui dependency at all; the editor is a separate consumer of it.
- commits
- 155
- own LOC
- ~11.2k
- surviving renderer lines mine
- 91%
The link points at branch experimental, which holds the final state of the code described here. It is mid-refactor and does not build the editor; main, at January 2023, is the last state that runs.
2023
Solo · archived
A ground-up Vulkan engine that turned into an experiment in what an ECS framework should look like in C++.
- A system is a free function whose parameter list declares its dependencies; the scheduler deduces at compile time whether each parameter is a query, resource or event and whether it is read or written.
- Registration fails if two systems in the same stage would conflict, and the error text tells you to move one to a different stage.
- Queries specialize over entt: one component picks a view, several pick a group, and the read/write id sets are constexpr.
- The renderer stores the scene as a RenderPass → Shader → Material → Mesh tree, so state changes are minimized structurally rather than by sorting each frame.
- Per-frame descriptor pool chains that grow on exhaustion, VMA-backed allocation, and a light manager with O(1) swap-remove and a dirty list so only moved lights re-upload.
- commits
- 100
- branches / merged PRs
- 17 / 12
- own LOC
- ~5.8k
The conflict checker establishes the invariants that make parallel execution safe; the scheduler itself is single-threaded.
Abandoned mid-refactor while extracting the renderer into a plugin.