Skip to main content
C++DirectX 12Game EngineRenderingPythonMCP

DeltaEngine

A DirectX 12 game engine and editor written in C++23, with its own reflection code generator, garbage collector, render graph, and an MCP bridge that lets AI agents edit scenes through the editor's undo system.

DeltaEngine

Overview

DeltaEngine is a Windows x64 game engine built on DirectX 12, with an integrated editor. The engine and editor are compiled in CMake with C++23 standard, and the build tooling is Python 3.12.

The Delta Engine under control by Claude.

This page is an outline of the engine’s systems, with one paragraph on each. Several of them will get their own detail pages later.

TargetKind
DeltaEngineShared library
DeltaEditorShared library
DeltaEditorLaunchExecutable
DeltaEngineTestsGTest suite
DeltaEditorTestsGTest suite

Engine

Core object model

Everything in the engine derives from DObject. A GameObject holds components: DComponent for non-spatial behavior and SceneComponent for anything with a transform, which forms the parent/child hierarchy. DScene is the serialized form of a scene and DWorld is the runtime container it loads into, with WorldContext, Camera, Skybox, and Time alongside. Objects and assets carry a stable UUID, and the core asset objects are DMesh, DMaterial, DTexture, and DShader.

Garbage collection

GCManager runs a two-phase mark and sweep that moves through Idle, Marking, and Sweeping states. Objects live in DObjectRegistry, a versioned slot table that also holds the root set, so a DObjectHandle can detect when its slot has been reused and resolve to null instead of a different object. StrongDObjectPtr<T> roots an object for as long as it is alive, and WeakDObjectPtr<T> nulls itself when the target is collected. Destruction goes through BeginDestroy, IsReadyForFinishDestroy, and FinishDestroy, and the engine runs one synchronous collection at shutdown.

Reflection

Classes, structs, enums, properties, and functions are annotated with DCLASS, DSTRUCT, DENUM, DPROPERTY, DFUNCTION, and DGENERATED_BODY. At build time these become metadata (DClass, DStruct, DProperty, DFunction, DEnum), with property specializations for scalars, strings, math types, object pointers, vectors, enums, and bulk data. ReflectionRegistry looks up types and instantiates them at runtime, and reflected functions are called through generated thunks. The reference walk built on this metadata is what the garbage collector and the serializer both use to find object references. About 37 engine and editor classes are reflected today.

Serialization

JsonAssetArchive reads and writes any reflected object to JSON by walking its properties. Large binary payloads such as mesh and texture data go through TBulkData and BulkDataHandle instead of the JSON body, and ScriptPointer resolves references between objects. ObjectSnapshot captures a full or partial image of an object, which the editor uses for undo. Types that need to fix up state around a save or load implement ISerializationCallbackReceiver.

Asset system

A DPrimaryAsset is a loadable asset that owns the DObject instances inside it, with concrete types for scenes, static meshes, materials, textures, shaders, skyboxes, and post-process stacks. Runtime code talks to an IAssetDatabase found through AssetDatabaseLocator, which falls back to a NullAssetDatabase, while the editor registers EditorAssetDatabase. Importing starts at AssetImporter, which dispatches to ModelImporter (built on Assimp) or TextureImporter.

DirectX 12 RHI

The graphics layer wraps D3D12 in its own types: Device, CommandQueue, CommandList, and SwapChain, a family of buffer and texture resources, and shader resource, unordered access, and constant buffer views. Descriptors come from paged DescriptorAllocator heaps plus a DynamicDescriptorHeap for per-draw bindings. ResourceStateTracker records resource states so transitions are issued correctly, and RenderResourceReleaseQueue defers GPU resource teardown until the GPU is finished with them. DXGraphicsContext is the per-frame context passed down the render stack, and DXRenderManager owns the offscreen scene render target.

Render graph

Frames are built as a RenderGraph. Each pass declares the textures it reads and writes through RenderGraphBuilder, and the graph owns both imported textures and transient ones pulled from TransientTexturePool. Compiling the graph inserts resource barriers and clears automatically, so passes don’t manage state transitions themselves. The built-in passes cover the G-buffer, deferred lighting, forward scene rendering, transparency, shadows, the skybox, MSAA resolve, and post-processing.

Rendering pipeline and renderers

RenderPath switches between forward and deferred rendering. Scene components such as MeshRenderer and SpriteRenderer hand the renderer proxy objects: MeshRenderProxy, CameraRenderProxy, SkyboxRenderProxy, and one proxy type per light. Transparent draws are sorted and submitted through TransparentDrawEntry. DefaultTextures supplies fallbacks for unbound material slots, and MaterialConstants defines the material flags, texture slots, and constant buffer layout shared with the shaders.

Lighting and shadows

The engine has directional, point, and spot lights, all deriving from LightComponent. ShadowPassManager renders shadow maps into a ShadowAtlas whose regions are handed out by ShadowMapAllocator, and point lights render into a ShadowCubeArray. Shadows are filtered with PCSS for contact-hardening soft edges.

PBR and image-based lighting

Materials are physically based, with base color, metallic, roughness, emissive color and intensity, and an alpha cutoff, and each material renders as Opaque, Masked, or Transparent. IBLBaker generates an irradiance cube, a prefiltered specular cube, and a BRDF lookup table from the skybox, and bakes again when the skybox changes.

Post-processing

A PostProcessStack is an ordered, reflected list of PostProcessPass objects, saved as a PA_PostProcessStack asset. The shipped passes are tonemapping, bloom, color grading, vignette, and a passthrough.

Shaders

Shaders are written in Slang and compiled at runtime through CompileSlangStage; the older CompileHLSLStage path is still there. The shader library is split into sets: standard and PBR object shading, the G-buffer and deferred lighting, IBL baking, shadow depth and PCSS sampling, one shader per post-process pass, the skybox, and a toon shader.

Logging

Logging sits on spdlog and follows Unreal’s model of named categories. Each DLogCategory has its own level from VeryVerbose to Fatal, and LoggingManager owns the sinks, accepts new sinks at runtime, and can override the level globally. Code declares categories with DECLARE_LOG_CATEGORY and DEFINE_LOG_CATEGORY and writes through DLOG and DLOG_IF.

Core utilities

The core library has single-cast, multicast, and dynamic delegates with DelegateHandle for unbinding, file IO through IOManager (using lodepng and stb_image), engine-wide EngineSettings, an assertion layer, math and string helpers, and a ThreadSafeQueue.

Editor

Application shell

EditorMain drives the frame loop and EditorCore holds the editor’s central state. Each frame runs PreTick, Tick, event processing, pending MCP requests, animation, rendering, and present, in that order. EditorRenderManager composes the ImGui chrome and dockspace and blits the scene texture into the viewport. Selection and session state live in their own objects, so panels share one selection model and the session persists between runs. The editor can also run headless for tests and CI.

UI

The fixed chrome is a header, a main toolbar, and a status bar around a dockspace. The docked windows are the viewport (fly camera, ImGuizmo transform gizmos, and viewport presets), a world outliner with filtering, a components hierarchy, a details inspector, and an asset browser. The details panel is driven entirely by reflection: property widgets for scalars, strings, vectors, colors, enums, and object references are chosen from the property type, and DFUNCTION methods appear as buttons. EditorTheme holds the styling tokens.

Commands and undo

Every scene edit is an EditorCommand with Execute, Undo, Redo, Serialize, and Deserialize. EditorCommandManager keeps undo and redo stacks 100 entries deep, and commands register themselves with EditorCommandRegistry through CommandRegistrar<T>. The concrete commands cover creating, deleting, and duplicating game objects, adding and removing components, setting properties, renaming, reparenting, editing post-process stacks, and renaming assets. Commands serialize to JSON, which means the undo stack can be saved and replayed.

Animation

EditorAnimationManager ticks in-flight tweens every frame. A TransformAnimationSession animates several transform channels of one object at once, and ViewportCameraAnimation moves the editor camera, both using curves from the Easing library. When a transform session finishes, it commits as a single batched undo entry instead of one entry per frame.

MCP integration

The editor exposes itself to AI agents over the Model Context Protocol. On the C++ side, McpSocketServer is an Asio TCP server on port 57340 that speaks newline-delimited JSON to one client. Requests are queued and drained on the main thread each frame, so engine state is only ever touched from one thread. McpQueryRouter sends each request to one of the pluggable IMcpSystem implementations: scene, assets, reflection, selection, undo history, viewport, project, lights, post-process, log, and a few shared ones. Queries are read-only and commands go through the undo system. Transform and light intensity changes can take a duration_seconds and tween instead of snapping. A Python FastMCP server in Tools/DeltaMCP fronts the bridge with three tools, list_operations, describe_operations, and execute_batch, backed by a JSON schema per system.

Tooling and infrastructure

Tooling

DeltaHeaderTool is the Python code generator behind reflection. It first scans headers as text to find annotated files, then parses those in parallel with libclang, and emits a .generated.h and .generated.cpp pair per header plus a CMake source manifest. It runs incrementally on file timestamps as part of every build. DeltaCmd is the command-line front end for list, configure, build, run, test, and header, reading presets, targets, and paths from one registry; it bootstraps the Visual Studio developer environment and has an --automatic mode for non-interactive use. Python 3.12 and LLVM libclang are bundled with the repository, and both tools have pytest suites.

Testing

DeltaEngineTests and DeltaEditorTests are GoogleTest suites. Engine tests cover reflection, serialization, assets, the object core and GC, delegates, IO, logging, and graphics, including render graph compilation. GPU tests run against a real D3D12 device, with fixtures that build scenes, read back GPU output, and validate D3D12 usage. Editor tests cover commands and the undo stack, save and load, each MCP system, selection, windows and panels, animation, the asset importer, and serialization round trips and compatibility. A headless EditorCoreFixture lets most of them run without a window or GPU.

Build and CI

The build is CMake and Ninja with MSVC C++23 and /MP parallel compilation, with reflection code generation wired into both configure and build. GitHub Actions runs on self-hosted Windows runners: DeltaCmd self-tests, DeltaMCP tests, configure, an editor build, then building and running the engine and editor test suites. The build tree and generated reflection headers are cached per branch.

Third-party dependencies

AreaLibraries
RenderingDirectX-Headers, DirectX Agility SDK, DirectXTK12, DirectXTex, DXC, Slang
Platform and UISDL3, Dear ImGui, ImGuizmo
AssetsAssimp, stb_image, lodepng
InfrastructureAsio, nlohmann/json, spdlog, WinPixEventRuntime
TestingGoogleTest