Repository navigation
Engine Architecture Flowchart
Complete visual guide to how SparkEngine works, from boot to shutdown.
Generated from 726 headers, 600 source files, 79 ECS components, 11 ECS systems, 64 editor panels, 6 RHI backends.
- Top-Level Overview
- Startup & Initialization
- Main Game Loop (Per-Frame)
- ECS Pipeline
- Rendering Pipeline
- RHI Abstraction Layer
- Physics Pipeline (Jolt)
- Audio Pipeline (XAudio2)
- AI & Navigation
- Animation System
- Networking Architecture
- Scripting (AngelScript)
- World Streaming & Origin Rebasing
- Editor Architecture (SparkEditor)
- Game Module Lifecycle
- Supporting Subsystems
- Shutdown Sequence
- SparkConsole (External Process)
Three executables and dynamically loaded game modules, all connected through EngineContext as the central service locator.
┌──────────────────────────────────────────────────────────────────┐
│ SparkEngine Ecosystem │
└──────────────────────────────────────────────────────────────────┘
┌────────────────────┐ ┌────────────────────┐ ┌────────────────┐
│ SparkEngine.exe │ │ SparkEditor.exe │ │ SparkConsole │
│ (Runtime Host) │ │ (Editor + Engine) │ │ (External UI) │
│ │ │ │ │ │
│ - Win32/SDL2 host │ │ - Dear ImGui UI │ │ - Pipe I/O │
│ - Windowed or │ │ - 64 editor panels │ │ - Command input │
│ headless mode │ │ - Engine embedded │ │ - Log display │
│ - Game loop owner │ │ - Live viewport │ │ │
└────────┬───────────┘ └────────┬───────────┘ └───────┬────────┘
│ │ │
│ ┌──────────────────┘ stdin/stdout │
│ │ pipes │
▼ ▼ │
┌──────────────────────────────────────────┐ │
│ EngineContext (Service Locator) │◄─────────────┘
│ │ (via ConsoleProcessManager)
│ GetGraphics() → GraphicsEngine* │
│ GetInput() → InputManager* │
│ GetPhysics() → PhysicsSystem* │
│ GetAudio() → AudioEngine* │
│ GetAI() → AISystem* │
│ GetAnimation() → AnimationSystem* │
│ GetNetwork() → NetworkManager* │
│ GetScriptEngine()→ AngelScriptEngine* │
│ GetSaveSystem() → SaveSystem* │
│ GetTimer() → Timer* │
│ GetEventBus() → EventBus* │
│ GetSceneManager()→ SceneManager* │
│ GetCoroutineScheduler()→ Scheduler* │
│ │
│ RegisterSystem<T>() / GetSystem<T>() │
└────────────────────┬─────────────────────┘
│
┌─────────────┼──────────────┐
▼ ▼ ▼
┌────────────┐ ┌───────────┐ ┌────────────┐
│ SparkGame │ │ Module 2 │ │ Module N │
│ (IModule) │ │ (IModule) │ │ (IModule) │
│ .dll/.so │ │ .dll/.so │ │ .dll/.so │
└────────────┘ └───────────┘ └────────────┘
Key files:
-
SparkEngine/Source/Core/SparkEngine.cpp— Runtime host entry point -
SparkEngine/Source/Core/EngineContext.h— Service locator singleton -
SparkEditor/Source/main.cpp— Editor entry point -
SparkConsole/src/main.cpp— Console entry point -
SparkEngine/Source/Core/ModuleManager.cpp— Dynamic module loading
The engine boots through a strict initialization order. Dependencies flow top-down — each step requires the ones above it.
┌──────────┐
│ main() │
└────┬─────┘
│
┌────────▼────────┐
│ SetupCrashHandler│
└────────┬────────┘
│
┌────────▼─────────────┐
│ ParseCommandLine │
│ -headless, -test, │
│ -window-size, etc. │
└────────┬─────────────┘
│
┌────────────┴────────────┐
▼ ▼
┌───────────────────┐ ┌────────────────────────┐
│ WINDOWED PATH │ │ HEADLESS PATH │
└────────┬──────────┘ └───────────┬────────────┘
│ │
┌────────▼──────────┐ ┌───────────▼────────────┐
│ CreateWindow │ │ AllocConsole │
│ (Win32/SDL2) │ └───────────┬────────────┘
└────────┬──────────┘ │
│ ┌─────────▼──────────────┐
┌────────▼──────────┐ │ InitHeadlessContext │
│ InitGraphics │ │ (no GPU, no input) │
│ (RHI backend) │ └─────────┬──────────────┘
└────────┬──────────┘ │
│ ┌──────────▼──────────────┐
┌────────▼──────────┐ │ InitSaveSystem │
│ InitInput │ └──────────┬──────────────┘
│ (InputManager) │ │
└────────┬──────────┘ ┌──────────▼──────────────┐
│ │ InitConsole │
┌────────▼──────────┐ └──────────┬──────────────┘
│ InitTimer │ │
└────────┬──────────┘ ┌──────────▼──────────────┐
│ │ LoadHeadlessModules │
┌────────▼──────────────┐ └──────────┬──────────────┘
│ InitEngineContext │ │
│ (create singleton) │ ┌──────────▼──────────────┐
└────────┬──────────────┘ │ Fixed 60Hz Tick Loop │
│ │ (sleep-regulated) │
┌────────▼──────────────┐ └─────────────────────────┘
│ RegisterCoreSubsystems│
│ (via EngineSetup) │
└────────┬──────────────┘
│
┌────────▼──────────────┐
│ InitJobSystem │
│ (thread pool) │
└────────┬──────────────┘
│
┌────────▼──────────────────────────┐
│ InitGameplaySubsystems │
│ WeatherSystem, TimeOfDaySystem, │
│ UISystem, DialogueSystem, ModSystem│
└────────┬──────────────────────────┘
│
┌────────▼──────────────┐
│ InitSaveSystem │
│ + CoroutineScheduler │
└────────┬──────────────┘
│
┌────────▼──────────────┐
│ InitAudioEngine │
│ (XAudio2) │
└────────┬──────────────┘
│
┌────────▼──────────────┐
│ LoadAndInitModules │
│ (dlopen / LoadLibrary) │
│ Call OnLoad() each │
└────────┬──────────────┘
│
┌────────▼───────────────────────────┐
│ InitConsole │
│ ├─ SimpleConsole::Initialize() │
│ ├─ ConsoleProcessManager (spawn │
│ │ SparkConsole.exe subprocess) │
│ ├─ InitDebugSystems() │
│ └─ InitGameplaySystems() │
└────────┬───────────────────────────┘
│
┌────────▼──────────────────┐
│ Publish EngineStartEvent │
└────────┬──────────────────┘
│
┌────────▼──────────────────┐
│ MAIN LOOP READY │
└───────────────────────────┘
Key files:
-
SparkEngine/Source/Core/SparkEngine.cpp—wWinMain(),main(),InitInstance(),InitEngineContext() -
SparkEngine/Source/Core/EngineBootstrap.h—EngineSetup::RegisterCoreSubsystems() -
SparkEngine/Source/Core/GameplaySystemLifecycle.cpp—InitGameplaySystems() -
SparkEngine/Source/Utils/ConsoleProcessManager.h— subprocess management
Every frame follows this exact sequence. Each subsystem update is wrapped in SPARK_GUARDED_UPDATE() for exception isolation — a crash in one system won't take down the engine.
┌──────────────────────────────────────────────────────────┐
│ FRAME START │
└────────────────────────┬─────────────────────────────────┘
│
┌───────────▼───────────┐
│ PeekMessage() / │ ◄── Win32 or SDL2
│ SDL_PollEvent() │ non-blocking
│ (process OS events) │
└───────────┬───────────┘
│
┌───────────▼───────────┐
│ Timer::GetDeltaTime() │
└───────────┬───────────┘
│
┌───────────▼───────────┐
│ DeltaSmoother │ ◄── Prevents physics
│ (smooth frame spikes) │ jitter from spikes
└───────────┬───────────┘
│
┌───────────▼────────────────┐
│ FixedTimestepAccumulator │ ◄── Deterministic
│ .Advance(smoothedDt) │ fixed-rate updates
└───────────┬────────────────┘
│
┌───────────▼───────────┐
│ InputManager::Update() │
│ (keyboard, mouse, │
│ gamepad polling) │
└───────────┬───────────┘
│
┌───────────▼───────────────────┐
│ ModuleManager::UpdateAll(dt) │ ◄── Game modules
│ (calls OnUpdate + OnFixedUpdate│ get first crack
│ on each loaded IModule) │
└───────────┬───────────────────┘
│
┌───────────▼───────────────────┐
│ ModuleManager::RenderAll() │
│ (calls OnRender on each module)│
└───────────┬───────────────────┘
│
┌───────────▼────────────────────┐
│ PollModuleHotReload() │ ◄── Check for
│ (detect changed DLLs, reload) │ recompiled modules
└───────────┬────────────────────┘
│
┌───────────▼────────────────────┐
│ UpdateGameplaySystems(dt) │
│ ┌────────────────────────────┐ │
│ │ Physics → Animation → AI │ │
│ │ → Audio → Lifecycle │ │
│ │ → Particles → Projectiles │ │
│ │ → Scripting → Coroutines │ │
│ │ → Weather → TimeOfDay │ │
│ │ → Streaming → Networking │ │
│ └────────────────────────────┘ │
└───────────┬────────────────────┘
│
┌───────────▼────────────────────┐
│ UpdateDebugSystems(dt) │
│ (profiler, debug draw, │
│ performance stats) │
└───────────┬────────────────────┘
│
┌───────────▼────────────────────┐
│ ConsoleProcessManager │
│ ::ProcessCommands() │
│ (read pipe from SparkConsole) │
└───────────┬────────────────────┘
│
┌───────────▼───────────┐
│ Console::Update() │
│ (flush log messages │
│ to SparkConsole) │
└───────────┬───────────┘
│
┌───────────▼───────────┐
│ Increment frame count │
└───────────┬───────────┘
│
┌───────────▼───────────┐
│ FRAME END │
│ (loop back to top) │
└───────────────────────┘
Key files:
-
SparkEngine/Source/Core/SparkEngine.cpp—RunWindowedMainLoop(),RunSDL2MainLoop(),TickFrame()
SparkEngine uses EnTT as its entity-component-system backbone. The SystemManager owns all systems and calls them in a strict order each frame.
┌─────────────────────────────────────────────────────────────┐
│ EnTT Registry (World) │
│ Entities are just IDs. Components are data. Systems run. │
└──────────────────────────┬──────────────────────────────────┘
│
SystemManager::UpdateAll(dt) called each frame
│
┌──────────────────────▼──────────────────────────┐
│ CORE SYSTEMS (ordered) │
│ │
│ ┌─────────────────────────────────────────┐ │
│ │ 1. PhysicsUpdateSystem │ │
│ │ Step Jolt simulation │ │
│ │ Write → Transform, RigidBody │ │
│ └──────────────────┬──────────────────────┘ │
│ ▼ │
│ ┌─────────────────────────────────────────┐ │
│ │ 2. AnimationUpdateSystem │ │
│ │ Evaluate skeleton + state machines │ │
│ │ Write → bone matrices │ │
│ └──────────────────┬──────────────────────┘ │
│ ▼ │
│ ┌─────────────────────────────────────────┐ │
│ │ 3. AIUpdateSystem │ │
│ │ Tick behavior trees │ │
│ │ Read → Transform; Write → Velocity │ │
│ └──────────────────┬──────────────────────┘ │
│ ▼ │
│ ┌─────────────────────────────────────────┐ │
│ │ 4. AudioUpdateSystem │ │
│ │ Update 3D source positions │ │
│ │ Read → Transform, AudioSource │ │
│ └──────────────────┬──────────────────────┘ │
│ ▼ │
│ ┌─────────────────────────────────────────┐ │
│ │ 5. LifecycleSystem │ │
│ │ Process health, death, active states │ │
│ │ Read/Write → Health, Active │ │
│ └──────────────────┬──────────────────────┘ │
│ ▼ │
│ ┌─────────────────────────────────────────┐ │
│ │ 6. RenderSystem │ │
│ │ Submit draw calls to GPU │ │
│ │ Read → Transform, MeshRenderer │ │
│ └─────────────────────────────────────────┘ │
│ │
│ AUXILIARY SYSTEMS (also ordered) │
│ ┌─────────────────────────────────────────┐ │
│ │ ParticleUpdateSystem (emitter advance) │ │
│ │ DecalSystem (lifetime / fade-out) │ │
│ │ ProjectileSystem (movement + gravity) │ │
│ │ SplineFollowerSystem (path advancement) │ │
│ │ AbilityUpdateSystem (cooldown ticks) │ │
│ └─────────────────────────────────────────┘ │
└──────────────────────────────────────────────────┘
┌─ CORE ───────────────────────────────────────────────┐
│ Transform, NameComponent, ActiveComponent, TagComponent│
│ MeshRenderer, Camera, Camera2D, Script │
└──────────────────────────────────────────────────────┘
┌─ PHYSICS ────────────────────────────────────────────┐
│ RigidBodyComponent, ColliderComponent, │
│ CharacterControllerComponent, PhysicsJointComponent, │
│ RagdollComponent, SoftBodyComponent, VehicleComponent│
└──────────────────────────────────────────────────────┘
┌─ GAMEPLAY ───────────────────────────────────────────┐
│ HealthComponent, AbilityComponent, ProjectileComponent│
│ DestructibleComponent, InteractionComponent, │
│ InventoryTag, QuestTrackerTag, WeatherComponent │
└──────────────────────────────────────────────────────┘
┌─ AI & NAV ───────────────────────────────────────────┐
│ AIComponent, NavRegionComponent, NavLinkComponent, │
│ NavObstacleComponent, SpawnPointComponent, │
│ CoverPointComponent, TacticalPointComponent │
└──────────────────────────────────────────────────────┘
┌─ AUDIO ──────────────────────────────────────────────┐
│ AudioSourceComponent, AudioListenerComponent, │
│ AudioReverbZoneComponent │
└──────────────────────────────────────────────────────┘
┌─ ANIMATION ──────────────────────────────────────────┐
│ AnimationController, ParticleEmitterComponent, │
│ SpriteAnimator, SpriteAnimationClip │
└──────────────────────────────────────────────────────┘
┌─ LIGHTING & FX ──────────────────────────────────────┐
│ LightComponent, LightProbeComponent, │
│ ReflectionProbeComponent, PostProcessVolumeComponent,│
│ DecalComponent, FogVolumeComponent, WindZoneComponent│
└──────────────────────────────────────────────────────┘
┌─ TERRAIN & WORLD ────────────────────────────────────┐
│ TerrainComponent, AreaBoundaryComponent, │
│ FoliageVolumeComponent, WaterPlaneComponent, │
│ BuoyancyVolumeComponent, ForceRegionComponent │
└──────────────────────────────────────────────────────┘
┌─ 2D ─────────────────────────────────────────────────┐
│ SpriteRenderer, RigidBody2D, Collider2D, │
│ TilemapComponent, NineSliceSprite, ParallaxLayer │
└──────────────────────────────────────────────────────┘
┌─ SPECIAL ────────────────────────────────────────────┐
│ NetworkIdentity, LODGroupComponent, OccluderComponent│
│ SpringArmComponent, CinematicTriggerComponent, │
│ DialogueTriggerComponent, TriggerVolumeComponent │
└──────────────────────────────────────────────────────┘
Key files:
-
SparkEngine/Source/Engine/ECS/Systems/ECSystems.h— System definitions and execution order -
SparkEngine/Source/Engine/ECS/Components/CoreComponents.h— Transform, MeshRenderer, Camera, Script -
SparkEngine/Source/Engine/ECS/Components/— All 12+ domain component headers
The deferred rendering pipeline uses a render graph for automatic resource management and pass ordering.
┌─────────────────────────────────────────────────────────────┐
│ ECS: RenderSystem::Update() │
│ Read Transform + MeshRenderer for each entity │
└─────────────────────────┬───────────────────────────────────┘
│
┌───────────▼───────────────┐
│ SceneRenderer::Submit() │
│ (accumulate draw commands) │
└───────────┬───────────────┘
│
┌───────────▼───────────────────────────┐
│ GraphicsEngine::BeginFrame() │
│ ├─ ConstantBufferRing.BeginFrame() │
│ ├─ GPUTimestampQuery.BeginFrame() │
│ ├─ ShadowAtlas.BeginFrame() │
│ └─ UpdateFrameConstants(view,proj,cam) │
└───────────┬───────────────────────────┘
│
┌───────────▼───────────────────────────┐
│ SceneRenderer::CullAndSort() │
│ ├─ BVH frustum culling │
│ ├─ Distance-based LOD assignment │
│ └─ Material-based draw call sorting │
└───────────┬───────────────────────────┘
│
┌────────────────▼────────────────┐
│ Build & Execute RenderGraph │
│ (compile → topological sort │
│ → dead-code elimination │
│ → resource aliasing │
│ → execute in dependency order) │
└────────────────┬────────────────┘
│
┌─────────────────────▼──────────────────────────┐
│ RENDER PASSES │
│ │
│ ┌───────────────────────────────────────┐ │
│ │ 1. SHADOW PASS │ │
│ │ For each shadow-casting light: │ │
│ │ ├─ Directional → Cascaded SM (CSM) │ │
│ │ ├─ Point → Cubemap (6-face) │ │
│ │ └─ Spot → Single depth map │ │
│ │ Techniques: PCF, VSM, PCSS │ │
│ │ → Write to ShadowAtlas tiles │ │
│ └──────────────────┬────────────────────┘ │
│ ▼ │
│ ┌───────────────────────────────────────┐ │
│ │ 2. GEOMETRY PASS (G-Buffer Fill) │ │
│ │ Render all visible meshes into: │ │
│ │ ├─ RT0: Albedo (RGB) + AO (A) │ │
│ │ ├─ RT1: Normal (RGB) + Roughness(A) │ │
│ │ ├─ RT2: Material (Metallic, etc.) │ │
│ │ └─ RT3: Motion Vectors │ │
│ │ Bind PBR materials per draw call │ │
│ └──────────────────┬────────────────────┘ │
│ ▼ │
│ ┌───────────────────────────────────────┐ │
│ │ 3. LIGHTING PASS (Full-Screen) │ │
│ │ ├─ Read G-buffers as SRVs │ │
│ │ ├─ ClusteredLightCulling::Update() │ │
│ │ │ ├─ Subdivide frustum (16x8x24) │ │
│ │ │ ├─ Assign lights to clusters │ │
│ │ │ └─ Upload cluster data to GPU │ │
│ │ ├─ Resolve accumulated lighting │ │
│ │ └─ Apply shadow atlas lookups │ │
│ │ → Output: HDR color texture │ │
│ └──────────────────┬────────────────────┘ │
│ ▼ │
│ ┌───────────────────────────────────────┐ │
│ │ 4. TRANSPARENT PASS │ │
│ │ Alpha-blended geometry (sorted) │ │
│ └──────────────────┬────────────────────┘ │
│ ▼ │
│ ┌───────────────────────────────────────┐ │
│ │ 5. POST-PROCESSING CHAIN │ │
│ │ │ │
│ │ SSAO (hemisphere sampling) │ │
│ │ │ │ │
│ │ ▼ │ │
│ │ SSR (ray march + HiZ refinement) │ │
│ │ │ │ │
│ │ ▼ │ │
│ │ VolumetricFog (froxel 160x90x64) │ │
│ │ ├─ InjectMedia (density/scatter) │ │
│ │ ├─ EvaluateLight (Henyey-Greenstein) │ │
│ │ └─ TemporalFilter (motion vectors) │ │
│ │ │ │ │
│ │ ▼ │ │
│ │ Bloom (downsample → upsample chain) │ │
│ │ │ │ │
│ │ ▼ │ │
│ │ Tonemapping + Color Grading │ │
│ │ (ACES/Filmic/Reinhard/Neutral) │ │
│ │ + Auto-exposure (histogram) │ │
│ │ │ │ │
│ │ ▼ │ │
│ │ TAA (temporal anti-aliasing) │ │
│ │ + FXAA, DoF, Vignette, Film Grain │ │
│ └──────────────────┬────────────────────┘ │
│ ▼ │
│ ┌───────────────────────────────────────┐ │
│ │ 6. TERRAIN PASS (ClipmapTerrain) │ │
│ │ ├─ Concentric LOD rings around cam │ │
│ │ ├─ Cell snapping for coherence │ │
│ │ ├─ GenerateMesh() per level │ │
│ │ └─ Heightmap sampling → GPU upload │ │
│ └──────────────────┬────────────────────┘ │
│ ▼ │
│ ┌───────────────────────────────────────┐ │
│ │ 7. GPU OCCLUSION CULLING (optional) │ │
│ │ ├─ Build HiZ mip chain from depth │ │
│ │ ├─ Compute shader: cull AABBs │ │
│ │ └─ DrawIndexedInstancedIndirect │ │
│ └──────────────────┬────────────────────┘ │
│ ▼ │
│ ┌───────────────────────────────────────┐ │
│ │ 8. UI PASS (ImGui / HUD) │ │
│ └──────────────────┬────────────────────┘ │
│ ▼ │
│ ┌───────────────────────────────────────┐ │
│ │ 9. DEBUG PASS (wireframe, normals, │ │
│ │ light counts, depth viz) │ │
│ └─────────────────────────────────────────┘ │
└─────────────────────┬──────────────────────────┘
│
┌───────────▼───────────────────────────┐
│ GraphicsEngine::EndFrame() │
│ ├─ ConstantBufferRing.EndFrame() │
│ ├─ GPUTimestampQuery.EndFrame() │
│ ├─ ShadowAtlas.EndFrame() (evict stale)│
│ └─ RHIBridge::Present(vsync) │
└───────────────────────────────────────┘
Key files:
-
SparkEngine/Source/Graphics/GraphicsEngine.h— Frame orchestration -
SparkEngine/Source/Graphics/RenderPipeline.h— Render graph execution -
SparkEngine/Source/Graphics/RenderGraph.h— DAG engine -
SparkEngine/Source/Graphics/ShadowAtlas.h— Shadow atlas management -
SparkEngine/Source/Graphics/ClusteredLightCulling.h— Light assignment -
SparkEngine/Source/Graphics/PostProcessingPipeline.h— Effect chain -
SparkEngine/Source/Graphics/ClipmapTerrain.h— Terrain LOD -
SparkEngine/Source/Graphics/GPUOcclusionCulling.h— HiZ culling -
SparkEngine/Source/Graphics/GPUDrivenRenderer.h— GPU-driven pipeline
The Rendering Hardware Interface abstracts all GPU APIs behind a unified interface. Backend selection happens once at startup.
┌───────────────────────────────────────────────┐
│ RHIFactory::DetectAvailableBackends() │
│ (probe system for supported APIs) │
└────────────────────┬──────────────────────────┘
│
┌────────────────────▼──────────────────────────┐
│ RHIFactory::GetRecommendedBackend() │
│ (platform-specific preference) │
└────────────────────┬──────────────────────────┘
│
┌────────────────────▼──────────────────────────┐
│ RHIFactory::CreateDevice(backend) │
│ Returns IRHIDevice* │
└────────────────────┬──────────────────────────┘
│
┌────────────────┼────────────────────────┐
│ │ │
▼ ▼ ▼
┌─────────┐ ┌────────────┐ ┌────────────────────┐
│ D3D11 │ │ D3D12 │ │ Vulkan │
│ Device │ │ Device │ │ Device │
│(primary)│ │(+DXR rays) │ │ (cross-platform) │
└─────────┘ └────────────┘ └────────────────────┘
▼ ▼ ▼
┌─────────┐ ┌────────────┐ ┌────────────────────┐
│ OpenGL │ │ Metal │ │ NullRHI │
│ Device │ │ Device │ │ Device │
│ (Linux) │ │ (macOS) │ │ (headless/test) │
└─────────┘ └────────────┘ └────────────────────┘
GPU-less Fallbacks:
┌───────────────────────────────────────────────┐
│ D3D11/D3D12 → WARP (software rasterizer) │
│ Vulkan → Lavapipe (Mesa) │
│ OpenGL → llvmpipe (Mesa) │
│ No GPU → NullRHIDevice (headless) │
└───────────────────────────────────────────────┘
┌─────────────────────────────────────────────────┐
│ IRHIDevice │
│ CreateBuffer(), CreateTexture(), │
│ CreateShader(), CreateSwapChain(), │
│ CreateCommandList() │
└──────────────────────┬──────────────────────────┘
│ creates
┌──────────┬───────┼───────┬──────────┐
▼ ▼ ▼ ▼ ▼
┌────────┐┌────────┐┌──────┐┌────────┐┌──────────┐
│IRHIBuf ││IRHITex ││IRHIS ││IRHICmd ││IRHISwap │
│ffer ││ture ││hader ││List ││Chain │
└────────┘└────────┘└──────┘└────────┘└──────────┘
Key files:
-
SparkEngine/Source/Graphics/RHI/RHIFactory.h— Backend detection and creation -
SparkEngine/Source/Graphics/RHI/RHIDevice.h— Abstract device interface -
SparkEngine/Source/Graphics/RHI/RHIBridge.h— Integration bridge -
SparkEngine/Source/Graphics/RHI/D3D11/D3D11Device.h— Primary backend
Jolt Physics runs in the PhysicsUpdateSystem at a fixed timestep. Results are written back to ECS Transform components.
┌──────────────────────────────────────────────────────┐
│ PhysicsUpdateSystem::Update(dt) │
└───────────────────────┬──────────────────────────────┘
│
┌───────────▼───────────────┐
│ JoltPhysicsSystem │
│ ::StepSimulation(fixedDt) │
└───────────┬───────────────┘
│
┌───────────────────▼───────────────────────┐
│ SIMULATION STEP │
│ │
│ ┌──────────────────────────────────┐ │
│ │ 1. BroadPhase │ │
│ │ AABB overlap detection │ │
│ │ (spatial partitioning) │ │
│ └──────────────┬───────────────────┘ │
│ ▼ │
│ ┌──────────────────────────────────┐ │
│ │ 2. NarrowPhase │ │
│ │ Exact collision detection │ │
│ │ GJK/EPA algorithms │ │
│ │ Generate contact manifolds │ │
│ └──────────────┬───────────────────┘ │
│ ▼ │
│ ┌──────────────────────────────────┐ │
│ │ 3. Contact Solving │ │
│ │ Resolve penetrations │ │
│ │ Apply friction/restitution │ │
│ └──────────────┬───────────────────┘ │
│ ▼ │
│ ┌──────────────────────────────────┐ │
│ │ 4. Constraint Solving │ │
│ │ Joints, ragdolls, vehicles │ │
│ │ Iterative solver │ │
│ └──────────────┬───────────────────┘ │
│ ▼ │
│ ┌──────────────────────────────────┐ │
│ │ 5. Integrate Positions │ │
│ │ Apply velocities to positions │ │
│ │ Apply angular velocities │ │
│ └──────────────────────────────────┘ │
└───────────────────┬───────────────────────┘
│
┌───────────▼───────────────────────┐
│ Write Back to ECS │
│ ├─ Transform.position ← body pos │
│ ├─ Transform.rotation ← body rot │
│ └─ RigidBody.velocity ← body vel │
└───────────────────────────────────┘
Physics Components:
┌──────────────────────────────────────────────────┐
│ RigidBodyComponent │ ColliderComponent │
│ (mass, velocity, │ (box, sphere, capsule, │
│ damping, gravity) │ mesh, heightfield) │
├──────────────────────┼───────────────────────────┤
│ CharacterController │ PhysicsJointComponent │
│ (ground detection, │ (hinge, slider, ball, │
│ step height, slope) │ fixed, distance) │
├──────────────────────┼───────────────────────────┤
│ RagdollComponent │ VehicleComponent │
│ (bone→body mapping) │ (wheels, suspension) │
├──────────────────────┼───────────────────────────┤
│ SoftBodyComponent │ ConstantForceComponent │
│ (deformable mesh) │ (continuous force/torque) │
└──────────────────────┴───────────────────────────┘
Key files:
-
SparkEngine/Source/Engine/ECS/Systems/ECSystems.h—PhysicsUpdateSystem -
SparkEngine/Source/Engine/ECS/Components/PhysicsComponents.h— All physics components
Audio runs after physics and animation so that 3D sound positions are up to date.
┌───────────────────────────────────────────────┐
│ AudioUpdateSystem::Update(dt) │
│ Read: AudioSourceComponent + Transform │
└──────────────────────┬────────────────────────┘
│
┌───────────▼───────────────┐
│ Update 3D Positions │
│ (source pos from Transform│
│ listener from Camera) │
└───────────┬───────────────┘
│
┌───────────▼───────────────┐
│ AudioEngine::Update() │
│ ├─ Apply 3D spatialization│
│ ├─ Apply distance atten. │
│ ├─ Apply reverb zones │
│ └─ Mix voices │
└───────────┬───────────────┘
│
┌───────────▼───────────────┐
│ XAudio2::SubmitSource │
│ Buffer() │
└───────────┬───────────────┘
│
┌───────────▼───────────────┐
│ Mastering Voice → Output │
└───────────────────────────┘
Audio Components:
┌────────────────────────────────────────────┐
│ AudioSourceComponent │
│ (clip, volume, pitch, loop, 3D/2D, │
│ min/max distance, rolloff) │
├────────────────────────────────────────────┤
│ AudioListenerComponent │
│ (position, forward, up — usually on Camera)│
├────────────────────────────────────────────┤
│ AudioReverbZoneComponent │
│ (bounds, reverb preset, mix level) │
└────────────────────────────────────────────┘
Key files:
-
SparkEngine/Source/Engine/ECS/Systems/ECSystems.h—AudioUpdateSystem SparkEngine/Source/Engine/ECS/Components/AudioComponents.h
The AI system uses behavior trees for decision making and Recast/Detour-style navmesh for pathfinding.
┌──────────────────────────────────────────────────────────┐
│ AIUpdateSystem::Update(dt) │
│ Read: AIComponent + Transform │
└─────────────────────────┬────────────────────────────────┘
│
┌─────────────────▼──────────────────┐
│ For each AI entity: │
│ │
│ ┌──────────────────────────────┐ │
│ │ PerceptionSystem::Update() │ │
│ │ ├─ Sight sense (ray/cone) │ │
│ │ ├─ Sound sense (radius) │ │
│ │ └─ Custom senses │ │
│ │ │ │
│ │ StimulusSource → AIComponent │ │
│ │ (perceived enemies, sounds) │ │
│ └──────────────┬───────────────┘ │
│ ▼ │
│ ┌──────────────────────────────┐ │
│ │ BehaviorTree::Tick() │ │
│ │ │ │
│ │ [Selector] │ │
│ │ ├─ [Sequence: Attack] │ │
│ │ │ ├─ HasTarget? │ │
│ │ │ ├─ InRange? │ │
│ │ │ └─ FireWeapon │ │
│ │ ├─ [Sequence: Chase] │ │
│ │ │ ├─ HasTarget? │ │
│ │ │ └─ MoveTo(target) │ │
│ │ └─ [Action: Patrol] │ │
│ │ └─ FollowPath │ │
│ └──────────────┬───────────────┘ │
│ ▼ │
│ ┌──────────────────────────────┐ │
│ │ NavMesh Pathfinding │ │
│ │ ├─ NavMeshQuery::FindPath() │ │
│ │ ├─ Path smoothing │ │
│ │ └─ Steering → Velocity │ │
│ └──────────────┬───────────────┘ │
│ ▼ │
│ Write: Velocity, Target, State │
└────────────────────────────────────┘
NavMesh Pipeline:
┌──────────────────────────────────────────────┐
│ Static geometry → Recast voxelization │
│ → Contour tracing → Polygon mesh generation │
│ → NavMesh baked (offline or runtime) │
│ │
│ NavRegionComponent — walkable area override │
│ NavLinkComponent — off-mesh connections │
│ NavObstacleComponent— dynamic obstacles │
│ CoverPointComponent — tactical cover spots │
│ TacticalPointComponent — strategic positions │
│ SpawnPointComponent — entity spawn locations │
└──────────────────────────────────────────────┘
Key files:
-
SparkEngine/Source/Engine/AI/AISystem.h— AI coordination -
SparkEngine/Source/Engine/AI/BehaviorTree.h— BT nodes and execution -
SparkEngine/Source/Engine/AI/NavMesh.h— Navigation mesh -
SparkEngine/Source/Engine/AI/PerceptionSystem.h— Sensory awareness
Skeletal animation with state machines, blend trees, and IK solving. Runs after physics so ragdoll results are available.
┌──────────────────────────────────────────────────────────┐
│ AnimationUpdateSystem::Update(dt) │
└─────────────────────────┬────────────────────────────────┘
│
┌───────────▼──────────────────────┐
│ For each AnimationController: │
│ │
│ ┌────────────────────────────┐ │
│ │ StateMachine::Evaluate() │ │
│ │ ├─ Check transitions │ │
│ │ │ (conditions, triggers) │ │
│ │ ├─ Advance current state │ │
│ │ └─ Cross-fade if changing │ │
│ └────────────┬───────────────┘ │
│ ▼ │
│ ┌────────────────────────────┐ │
│ │ BlendTree::Evaluate() │ │
│ │ ├─ Sample animation clips │ │
│ │ ├─ Blend weights (1D/2D) │ │
│ │ └─ Additive layers │ │
│ └────────────┬───────────────┘ │
│ ▼ │
│ ┌────────────────────────────┐ │
│ │ Skeletal Evaluation │ │
│ │ ├─ Compute local bone poses│ │
│ │ ├─ Multiply parent chain │ │
│ │ └─ Produce world-space │ │
│ │ bone matrices │ │
│ └────────────┬───────────────┘ │
│ ▼ │
│ ┌────────────────────────────┐ │
│ │ IK Solving │ │
│ │ ├─ Foot placement IK │ │
│ │ ├─ Hand IK (weapon grip) │ │
│ │ └─ Look-at IK (head/eyes) │ │
│ └────────────┬───────────────┘ │
│ ▼ │
│ ┌────────────────────────────┐ │
│ │ Final Pose → GPU Upload │ │
│ │ (bone matrices → skinning │ │
│ │ constant buffer) │ │
│ └────────────────────────────┘ │
└───────────────────────────────────┘
Key files:
-
SparkEngine/Source/Engine/Animation/— All animation subsystem files SparkEngine/Source/Engine/ECS/Components/AnimationComponents.h
UDP client/server with entity replication, client-side prediction, and lag compensation. Inspired by HeroEngine's AreaServer/WorldServer split.
┌──────────────────── CLIENT SIDE ────────────────────────┐
│ │
│ ┌─────────────┐ ┌──────────────────┐ │
│ │ Input │──▶│ ClientPrediction │ │
│ │ Capture │ │ (apply locally) │ │
│ └─────────────┘ └────────┬─────────┘ │
│ │ │
│ ┌────────▼─────────┐ │
│ │ PackMessage │ │
│ │ (ClientInput) │ │
│ └────────┬─────────┘ │
│ │ │
│ ┌────────▼─────────┐ │
│ │ UDPTransport │ │
│ │ ::Send() │──────────┐ │
│ └──────────────────┘ │ │
└─────────────────────────────────────────────────│─────┘
│
───────│───────
NETWORK
───────│───────
│
┌──────────────────── SERVER SIDE ────────────────│─────┐
│ │ │
│ ┌────────────────────┐ │ │
│ │ UDPTransport │◀───────┘ │
│ │ ::Receive() │ │
│ └────────┬───────────┘ │
│ │ │
│ ┌─────────────▼──────────────┐ │
│ │ NetworkManager │ │
│ │ ::ProcessMessages() │ │
│ └─────────────┬──────────────┘ │
│ │ │
│ ┌─────────────▼──────────────┐ │
│ │ EntityReplicator │ │
│ │ ::ApplyInput() │ │
│ │ (server-authoritative) │ │
│ └─────────────┬──────────────┘ │
│ │ │
│ ┌─────────────▼──────────────┐ │
│ │ Physics Simulation Step │ │
│ └─────────────┬──────────────┘ │
│ │ │
│ ┌─────────────▼──────────────┐ │
│ │ EntityReplicator │ │
│ │ ::BuildSnapshot() │ │
│ └─────────────┬──────────────┘ │
│ │ │
│ ┌─────────────▼──────────────┐ │
│ │ DeltaSnapshotManager │ │
│ │ ::Compress() │ │
│ │ (delta from last ACK'd) │ │
│ └─────────────┬──────────────┘ │
│ │ │
│ ┌────────▼─────────┐ │
│ │ UDPTransport │ │
│ │ ::Send() │──────────┐ │
│ └──────────────────┘ │ │
└─────────────────────────────────────────────────│─────┘
│
───────│───────
NETWORK
───────│───────
│
┌──────────────────── CLIENT RECEIVE ─────────────│─────┐
│ ┌────────────────────┐ │ │
│ │ UDPTransport │◀───────┘ │
│ │ ::Receive() │ │
│ └────────┬───────────┘ │
│ │ │
│ ┌─────────────▼──────────────┐ │
│ │ NetworkInterpolation │ │
│ │ ::BufferState() │ │
│ └─────────────┬──────────────┘ │
│ │ │
│ ┌─────────────▼──────────────┐ │
│ │ Reconcile with Prediction │ │
│ │ (replay unACK'd inputs) │ │
│ └─────────────┬──────────────┘ │
│ │ │
│ ┌─────────────▼──────────────┐ │
│ │ Render interpolated state │ │
│ └────────────────────────────┘ │
└────────────────────────────────────────────────────────┘
Server Architecture:
┌────────────────────────────────────────────────────────┐
│ WorldServer │
│ (multi-area coordinator) │
│ ┌──────────────┬──────────────┬──────────────┐ │
│ │ AreaServer │ AreaServer │ AreaServer │ │
│ │ (Zone A) │ (Zone B) │ (Zone C) │ │
│ │ physics + │ physics + │ physics + │ │
│ │ entities │ entities │ entities │ │
│ └──────────────┴──────────────┴──────────────┘ │
│ Entity handoff when player crosses area boundary │
└────────────────────────────────────────────────────────┘
Channel Types:
┌─────────────────────────────────────────────┐
│ Unreliable — position updates (fast) │
│ Reliable — ordered delivery │
│ ReliableOrdered — critical events (in order) │
└─────────────────────────────────────────────┘
Key files:
-
SparkEngine/Source/Engine/Networking/NetworkManager.h— Core multiplayer -
SparkEngine/Source/Engine/Networking/EntityReplicator.h— State replication -
SparkEngine/Source/Engine/Networking/ClientPrediction.h— Client prediction -
SparkEngine/Source/Engine/Networking/AreaServer.h— Single area simulation -
SparkEngine/Source/Engine/Networking/WorldServer.h— Multi-area coordination
Scripts are compiled from .as files, attached to entities via the Script component, and support hot-reload without restarting the engine.
┌──────────────────────── INITIALIZATION ──────────────────┐
│ │
│ ┌───────────────────────────────┐ │
│ │ AngelScriptEngine::Initialize()│ │
│ └───────────────┬───────────────┘ │
│ │ │
│ ┌───────────────▼───────────────┐ │
│ │ RegisterEngineAPI() │ │
│ │ ├─ print(string) │ │
│ │ ├─ createEntity() → EntityID │ │
│ │ ├─ getTransform(id) │ │
│ │ ├─ getKeyDown(key) → bool │ │
│ │ ├─ getKey(key) → bool │ │
│ │ └─ ... (full engine API) │ │
│ └───────────────┬───────────────┘ │
│ │ │
│ ┌───────────────▼───────────────┐ │
│ │ CompileScripts(.as files) │ │
│ │ Per-entity script instances │ │
│ │ Cache method pointers: │ │
│ │ Start(), Update(), OnCollision │ │
│ └───────────────────────────────┘ │
└──────────────────────────────────────────────────────────┘
┌──────────────────────── PER-FRAME ──────────────────────┐
│ │
│ ┌──────────────────────────────┐ │
│ │ ScriptSystem::Update(dt) │ │
│ └──────────────┬───────────────┘ │
│ │ │
│ ┌──────────────▼───────────────┐ │
│ │ For each Script component: │ │
│ │ ├─ Get cached Update() ptr │ │
│ │ ├─ Set dt argument │ │
│ │ └─ Execute() │ │
│ └──────────────────────────────┘ │
└──────────────────────────────────────────────────────────┘
┌──────────────────────── HOT-RELOAD ─────────────────────┐
│ │
│ FileWatcher detects .as change │
│ │ │
│ ┌────────▼────────────────────┐ │
│ │ ScriptHotReload │ │
│ │ ├─ Call Serialize() on all │ │
│ │ │ script instances │ │
│ │ ├─ Discard old module │ │
│ │ ├─ Recompile module │ │
│ │ ├─ Re-attach to entities │ │
│ │ └─ Call Deserialize() to │ │
│ │ restore state │ │
│ └─────────────────────────────┘ │
│ │
│ Context Separation: │
│ ┌────────┐ ┌────────┐ ┌────────┐ │
│ │ Shared │ │ Server │ │ Client │ │
│ │(both) │ │(auth.) │ │(visual)│ │
│ └────────┘ └────────┘ └────────┘ │
└──────────────────────────────────────────────────────────┘
Key files:
-
SparkEngine/Source/Engine/Scripting/AngelScriptEngine.h— VM wrapper -
SparkEngine/Source/Engine/Scripting/ScriptHotReload.h— Live recompilation -
SparkEngine/Source/Engine/Scripting/ScriptHookManager.h— Event binding
Large worlds require streaming adjacent areas in/out and periodically rebasing the floating-point origin to maintain precision far from the origin.
┌──────────── SeamlessAreaManager ────────────────────────┐
│ │
│ ┌──────────────────────────────────┐ │
│ │ Player Position + Velocity │ │
│ │ + Camera Direction │ │
│ └──────────────┬───────────────────┘ │
│ │ │
│ ┌──────────────▼───────────────────┐ │
│ │ Predictive Loading │ │
│ │ (3-second lookahead) │ │
│ │ Load radius: 500 units │ │
│ │ Unload radius: 800 units │ │
│ │ Max 2 concurrent loads │ │
│ └──────────────┬───────────────────┘ │
│ │ │
│ ┌──────────────▼───────────────────┐ │
│ │ Area State Machine │ │
│ │ │ │
│ │ Unloaded ──▶ Loading ──▶ Loaded │ │
│ │ ▲ │ │ │
│ │ └── Unloading ◀────────┘ │ │
│ └──────────────────────────────────┘ │
│ │
│ SceneTransitionManager handles scene loads/unloads │
└─────────────────────────────────────────────────────────┘
┌──────────── WorldOriginSystem ──────────────────────────┐
│ │
│ ┌──────────────────────────────────┐ │
│ │ Each frame: check player distance│ │
│ │ from current origin │ │
│ └──────────────┬───────────────────┘ │
│ │ │
│ distance > 5000? │
│ ┌─────┴─────┐ │
│ NO YES │
│ │ ┌─────▼──────────────────────┐ │
│ │ │ REBASE │ │
│ │ │ ├─ newOrigin = playerPos │ │
│ │ │ ├─ Shift ALL entity pos │ │
│ │ │ ├─ Notify callbacks: │ │
│ │ │ │ ├─ Physics bodies │ │
│ │ │ │ ├─ Audio sources │ │
│ │ │ │ ├─ Particle systems │ │
│ │ │ │ └─ NavMesh │ │
│ │ │ └─ accumulatedOffset += old │ │
│ │ └────────────────────────────┘ │
│ │ │
│ (no action) Transparent to gameplay: │
│ LocalToAbsolute() / AbsoluteToLocal()│
└─────────────────────────────────────────────────────────┘
Key files:
-
SparkEngine/Source/Engine/Streaming/SeamlessAreaManager.h— Area streaming -
SparkEngine/Source/Engine/World/WorldOriginSystem.h— Origin rebasing -
SparkEngine/Source/Engine/Streaming/DirectStorageLoader.h— GPU-direct loading
The editor is a standalone executable that embeds the engine and adds a Dear ImGui-based interface with 64 specialized panels.
┌───────────────── EditorApplication ─────────────────────┐
│ │
│ main() / wWinMain() │
│ │ │
│ ┌────▼─────────────────────────────────┐ │
│ │ CreateWindow (Win32 / SDL2) │ │
│ └────┬─────────────────────────────────┘ │
│ │ │
│ ┌────▼─────────────────────────────────┐ │
│ │ InitGraphics (D3D11 / OpenGL) │ │
│ └────┬─────────────────────────────────┘ │
│ │ │
│ ┌────▼─────────────────────────────────┐ │
│ │ InitImGui (platform + renderer) │ │
│ └────┬─────────────────────────────────┘ │
│ │ │
│ ┌────▼─────────────────────────────────┐ │
│ │ InitEditorUI │ │
│ │ ├─ CreateCorePanels() │ │
│ │ └─ CreateToolAndContentPanels() │ │
│ └────┬─────────────────────────────────┘ │
│ │ │
│ ┌────▼─────────────────────────────────┐ │
│ │ InitPlugins (editor extensions) │ │
│ └────┬─────────────────────────────────┘ │
│ │ │
│ ┌────▼─────────────────────────────────┐ │
│ │ EDITOR MAIN LOOP │ │
│ │ ┌─────────────────────────────────┐ │ │
│ │ │ ProcessMessages() (Win32/SDL2) │ │ │
│ │ └──────────────┬──────────────────┘ │ │
│ │ │ │ │
│ │ ┌──────────────▼──────────────────┐ │ │
│ │ │ ImGui_NewFrame() │ │ │
│ │ └──────────────┬──────────────────┘ │ │
│ │ │ │ │
│ │ ┌──────────────▼──────────────────┐ │ │
│ │ │ EditorUI::Render() │ │ │
│ │ │ (render all visible panels) │ │ │
│ │ └──────────────┬──────────────────┘ │ │
│ │ │ │ │
│ │ ┌──────────────▼──────────────────┐ │ │
│ │ │ PluginManager::RenderAll() │ │ │
│ │ └──────────────┬──────────────────┘ │ │
│ │ │ │ │
│ │ ┌──────────────▼──────────────────┐ │ │
│ │ │ ImGui::Render() + Present │ │ │
│ │ └─────────────────────────────────┘ │ │
│ └──────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────┘
Editor Panels (64 total):
┌────────────────────── CORE ─────────────────────────────┐
│ Hierarchy, Inspector, SceneView, GameView, Console, │
│ AssetBrowser, ProjectBrowser, ProjectSettings, Search │
└─────────────────────────────────────────────────────────┘
┌────────────────────── TOOLS ────────────────────────────┐
│ MaterialEditor, ParticleEditor, SplineEditor, │
│ DecalEditor, DestructionEditor, WeaponEditor, │
│ AbilityEditor, FPSTools, ObjectPlacement, │
│ PostProcessing, TriggerEditor, ConditionEditor │
└─────────────────────────────────────────────────────────┘
┌────────────────────── CONTENT ──────────────────────────┐
│ ScriptEditor, DialogueEditor, CinematicSequencer, │
│ LocalizationPanel, TilemapEditor, SpriteEditor, │
│ SpriteAnimationEditor │
└─────────────────────────────────────────────────────────┘
┌────────────────────── DEBUG ────────────────────────────┐
│ DebugVisualizer, EventMonitor, CoroutineDebug, │
│ SceneStatistics, Physics2D, Physics3D, AudioMixer │
└─────────────────────────────────────────────────────────┘
┌────────────────────── INFRASTRUCTURE ───────────────────┐
│ BuildCook, BuildPipeline, PlayModeToolbar, Workflow, │
│ GameModuleSelector, Collaboration, DedicatedServer, │
│ SaveSystem, Streaming, Replay, Modding, VRConfig, │
│ WeatherFog, TimeOfDay, UndoHistory │
└─────────────────────────────────────────────────────────┘
Collaborative Editing:
┌─────────────────────────────────────────────────────────┐
│ CollaborativeEditSession (WebSocket) │
│ ├─ User cursors + selections shared in real-time │
│ ├─ Entity lock/unlock for conflict prevention │
│ └─ Operation transform for concurrent edits │
└─────────────────────────────────────────────────────────┘
Key files:
-
SparkEditor/Source/Core/EditorApplication.h— Editor lifecycle -
SparkEditor/Source/Core/EditorUI.h— Panel registry and rendering -
SparkEditor/Source/Panels/— All 64 panel implementations SparkEditor/Source/Communication/CollaborativeEditSession.h
Game modules are compiled as separate DLLs/shared libraries. The engine loads them at runtime via ModuleManager, giving each module access to the full engine through EngineContext.
┌──────────────────── ENGINE SIDE ────────────────────────┐
│ │
│ ┌──────────────────────────────────┐ │
│ │ ModuleManager::LoadModule(path) │ │
│ └──────────────┬───────────────────┘ │
│ │ │
│ ┌──────────────▼───────────────────┐ │
│ │ dlopen() / LoadLibrary() │ │
│ └──────────────┬───────────────────┘ │
│ │ │
│ ┌──────────────▼───────────────────┐ │
│ │ CreateModule() (C export) │ │
│ │ Returns IModule* │ │
│ └──────────────┬───────────────────┘ │
│ │ │
│ ┌──────────────▼───────────────────┐ │
│ │ IModule::OnLoad(EngineContext*) │ │
│ │ Module initializes, registers │ │
│ │ console commands, subscribes to │ │
│ │ events, sets up gameplay │ │
│ └──────────────┬───────────────────┘ │
│ │ │
│ ┌───────────▼────────────────────────────┐ │
│ │ PER-FRAME CALLS │ │
│ │ │ │
│ │ ModuleManager::UpdateAll(dt) │ │
│ │ ├─ IModule::OnUpdate(dt) │ │
│ │ ├─ IModule::OnFixedUpdate() │ │
│ │ └─ IModule::OnRender() │ │
│ │ │ │
│ │ Also called when relevant: │ │
│ │ ├─ OnResize(width, height) │ │
│ │ ├─ OnPause() / OnResume() │ │
│ │ └─ OnImGui() (debug UI) │ │
│ └────────────────────────────────────────┘ │
│ │
│ ┌──────────────────────────────────┐ │
│ │ SHUTDOWN │ │
│ │ ├─ IModule::OnUnload() │ │
│ │ ├─ DestroyModule(ptr) (C export) │ │
│ │ └─ dlclose() / FreeLibrary() │ │
│ └──────────────────────────────────┘ │
└─────────────────────────────────────────────────────────┘
IModule Interface:
┌─────────────────────────────────────────────────────────┐
│ GetModuleInfo() → ModuleInfo (name, version, order) │
│ OnLoad(IEngineContext*) → bool │
│ OnUnload() │
│ OnUpdate(float deltaTime) │
│ OnFixedUpdate() │
│ OnRender() │
│ OnResize(int w, int h) │
│ OnPause() / OnResume() │
│ OnImGui() │
└─────────────────────────────────────────────────────────┘
Hot-Reload (development):
┌─────────────────────────────────────────────────────────┐
│ PollModuleHotReload() each frame │
│ ├─ Detect DLL timestamp change │
│ ├─ OnUnload() old module │
│ ├─ Copy DLL to temp, dlopen new copy │
│ └─ OnLoad() new module │
└─────────────────────────────────────────────────────────┘
Key files:
-
SparkEngine/Source/Core/ModuleManager.cpp— Module loading/unloading -
SparkEngine/Source/Core/ModuleManager.h— Module interface and loading -
GameModules/SparkGame/Source/Core/Main.cpp— Example module entry -
GameModules/SparkGame/Source/Core/SparkGame.h— Example module class
Quick-reference flowcharts for the remaining engine subsystems.
SaveSystem::Save(slotName)
│
├─ ComponentSerializerRegistry
│ (per-component serialize lambdas)
│ │
├───────▼──────────────────┐
│ Serialize all entities │
│ Transform, Health, │
│ RigidBody, etc. │
└───────┬──────────────────┘
│
┌───────▼──────────────────┐
│ SaveData (JSON) │
│ + miniz deflate compress │
└───────┬──────────────────┘
│
┌───────▼──────────┐
│ Write .sav file │
└──────────────────┘
Features: quicksave/quickload, rotating autosave (3 slots)
Builder Pattern:
StartCoroutine("name")
.Do([]{...})
.WaitForSeconds(2.0f)
.Do([]{...})
.Build()
C++20 Native:
GameCoroutine MyFunc() {
co_await WaitForSeconds(1.0f);
// resume here after 1 second
}
Scheduler: per-frame Update() advances all active coroutines
Cancellation: by name or StopAll()
UICanvas (root, one per viewport)
└─ UIPanel (layout: None / Horizontal / Vertical)
├─ UILabel (text display)
├─ UIButton (click handler)
├─ UIProgressBar (0.0 - 1.0)
├─ UIImageWidget (textured quad)
└─ UIPanel (nested containers)
Anchoring: 9 points + Stretch
Properties: position, size, visibility, opacity, z-order
RECORDING (configurable, default 20 fps):
Each tick → ReplayFrame {
timestamp, entity snapshots,
flags (Alive, Firing, Crouching...)
}
PLAYBACK:
Play / Pause / Rewind / FastForward / Seek
Camera: FreeCam, FollowCam, FirstPerson, KillCam
Kill cam: rewind N seconds, focus on entity
File: magic "RPLY", max 1M frames, 100k entities
ApplyDamage(entity, amount, hitPoint, hitDir)
│
├─ Update damage stage
│
├─ health <= 0?
│ YES → ForceDestroy()
│ │
│ ┌──────▼──────────────────┐
│ │ FracturePattern lookup │
│ │ Spawn debris pieces as │
│ │ ECS entities + physics │
│ │ (max 500 debris limit) │
│ │ Trigger particles + SFX │
│ └─────────────────────────┘
│
└─ NO → visual damage stage update
DialogueTriggerComponent → DialogueSystem::StartDialogue()
│
├─ Load dialogue tree (nodes + edges)
├─ Display speaker + text
├─ Show player choices (branching)
├─ Evaluate conditions (quest state, items)
└─ Execute actions (give item, advance quest)
LoadLanguage("en", "locales/en.json")
SetCurrentLanguage("en")
│
├─ StringTable: key → value mapping
├─ Get("hud.health") → "Health"
├─ Format("hud.ammo", 30, 120) → "Ammo: 30/120"
└─ Fallback to "en" for missing keys
OnLanguageChanged callback for UI refresh
LoadingScreen::Begin(tasks)
│
├─ LoadingTask { name, weight, execute() }
├─ Progress = weighted sum (0.0 → 1.0)
├─ Background image + rotating tips
├─ Minimum display time (no flash)
└─ OnComplete(success) callback
ModSystem::ScanForMods("mods/")
│
├─ Discover mod.json files
├─ Parse metadata (name, version, deps)
├─ AreDependenciesMet() check
│
├─ EnableMod(id) → load Scripts/, Assets/, Data/
└─ DisableMod(id) → unload
mod.json → Scripts/ → Assets/ → Data/ → Preview.png
VRSystem::Update()
│
├─ Head tracking (position + orientation)
├─ Per-eye rendering:
│ ├─ Left eye (view + proj matrix)
│ └─ Right eye (view + proj matrix)
├─ Motion controllers (2x):
│ ├─ Position, orientation, velocity
│ ├─ Triggers, grips, thumbstick, buttons
│ └─ Haptic feedback (amplitude + duration)
└─ Tracking space: Seated or RoomScale
MobilePlatform::Update()
│
├─ Touch events (Began/Moved/Ended/Cancelled)
├─ Gesture recognition:
│ Tap, DoubleTap, LongPress, Swipe, Pinch, Rotate
├─ Quality presets (Low/Medium/High/Auto)
│ (render scale, shadow res, draw budget, LOD bias)
├─ Screen: orientation, safe area (notch insets)
└─ Battery-aware scaling (reduce quality as drops)
Key files:
SparkEngine/Source/Engine/SaveSystem/SaveSystem.hSparkEngine/Source/Engine/Coroutine/CoroutineScheduler.hSparkEngine/Source/Engine/UI/UISystem.hSparkEngine/Source/Engine/Replay/ReplaySystem.hSparkEngine/Source/Engine/Destruction/DestructionSystem.h-
SparkEngine/Source/Engine/Dialogue/DialogueSystem.h(in Engine/Dialogue/) SparkEngine/Source/Engine/Localization/LocalizationSystem.hSparkEngine/Source/Engine/Loading/LoadingScreen.hSparkEngine/Source/Engine/Modding/ModSystem.hSparkEngine/Source/Engine/VR/VRSystem.hSparkEngine/Source/Engine/Mobile/MobilePlatform.h
Shutdown mirrors initialization in reverse order. The EngineShutdownEvent gives subsystems a chance to save state before teardown.
┌────────────────────────────────────────────────┐
│ ShutdownEngine() │
└───────────────────┬────────────────────────────┘
│
┌───────────▼───────────────────┐
│ Publish EngineShutdownEvent │
│ (subsystems save state) │
└───────────┬───────────────────┘
│
┌───────────▼───────────────────┐
│ ShutdownGameplaySystems() │
│ (Weather, TimeOfDay, UI, etc.) │
└───────────┬───────────────────┘
│
┌───────────▼───────────────────┐
│ ShutdownDebugSystems() │
│ (profiler, debug draw) │
└───────────┬───────────────────┘
│
┌───────────▼───────────────────┐
│ ModuleManager::ShutdownAll() │
│ (call OnUnload on each module) │
└───────────┬───────────────────┘
│
┌───────────▼───────────────────┐
│ SimpleConsole::Shutdown() │
│ (close pipe to SparkConsole) │
└───────────┬───────────────────┘
│
┌───────────▼───────────────────┐
│ ConsoleProcessManager │
│ ::Shutdown() │
│ (terminate SparkConsole.exe) │
└───────────┬───────────────────┘
│
┌───────────▼───────────────────┐
│ EventBus::ClearAll() │
│ (remove all subscribers) │
└───────────┬───────────────────┘
│
┌───────────▼───────────────────┐
│ ModuleManager::UnloadAll() │
│ (dlclose / FreeLibrary) │
└───────────┬───────────────────┘
│
┌───────────▼───────────────────┐
│ AudioEngine.reset() │
└───────────┬───────────────────┘
│
┌───────────▼───────────────────┐
│ ShutdownPhysics() │
│ (Jolt cleanup) │
└───────────┬───────────────────┘
│
┌───────────▼───────────────────┐
│ JobSystem::Shutdown() │
│ (drain queue, join threads) │
└───────────┬───────────────────┘
│
┌───────────▼───────────────────┐
│ EngineContext::ResetOwned() │
│ EventBus.reset() │
│ Input.reset() │
│ Graphics.reset() │
│ Timer.reset() │
└───────────┬───────────────────┘
│
┌───────────▼───────────────────┐
│ Clear debug hooks │
│ Process exits cleanly │
└───────────────────────────────┘
Key files:
-
SparkEngine/Source/Core/SparkEngine.cpp—ShutdownEngine() -
SparkEngine/Source/Core/GameplaySystemLifecycle.cpp—ShutdownGameplaySystems()
SparkConsole is a separate executable that communicates with the engine via stdin/stdout pipes. It provides an interactive command-line interface without blocking the engine's main loop.
┌──────────── ENGINE SIDE ────────────────────────────────┐
│ │
│ ┌──────────────────────────────────────┐ │
│ │ ConsoleProcessManager::Initialize() │ │
│ │ ├─ CreateProcess("SparkConsole.exe") │ │
│ │ └─ SetupPipes(stdin, stdout) │ │
│ └──────────────────┬───────────────────┘ │
│ │ │
│ Each frame: │ │
│ ┌──────────────────▼───────────────────┐ │
│ │ ConsoleProcessManager │ │
│ │ ::ProcessCommands() │ │
│ │ ├─ Read pipe for incoming commands │ │
│ │ └─ Execute via SimpleConsole │ │
│ └──────────────────┬───────────────────┘ │
│ │ │
│ ┌──────────────────▼───────────────────┐ │
│ │ SimpleConsole::Update() │ │
│ │ ├─ Write log messages to pipe │ │
│ │ │ (engine → console process) │ │
│ │ └─ Flush buffered output │ │
│ └──────────────────────────────────────┘ │
└──────────────────────────┬──────────────────────────────┘
│
stdin/stdout pipes
│
┌──────────── CONSOLE SIDE ───────────────┬───────────────┐
│ │ │
│ ┌──────────────────────────────────┐ │ │
│ │ main() → ConsoleApp::Run() │ │ │
│ └──────────────┬───────────────────┘ │ │
│ │ │ │
│ ┌─────────▼──────────┐ │ │
│ │ Detect pipe mode │ │ │
│ │ (stdin is a pipe?) │ │ │
│ └────┬──────────┬────┘ │ │
│ YES NO │ │
│ │ │ │ │
│ ┌─────────▼────┐ ┌──▼──────────────┐ │ │
│ │ PIPE MODE │ │ STANDALONE MODE │ │ │
│ │ │ │ │ │ │
│ │ Spawn: │ │ Blocking getline │ │ │
│ │ ├─ Engine │ │ for user input │ │ │
│ │ │ input │ │ Execute commands │ │ │
│ │ │ thread │ │ locally │ │ │
│ │ └─ Keyboard │ │ │ │ │
│ │ input │ │ │ │ │
│ │ thread │ │ │ │ │
│ │ │ │ │ │ │
│ │ Main loop: │ │ │ │ │
│ │ sleep 100ms │ │ │ │ │
│ │ (threads do │ │ │ │ │
│ │ the work) │ │ │ │ │
│ └──────────────┘ └──────────────────┘ │ │
└─────────────────────────────────────────────────────────┘
Communication Protocol:
┌─────────────────────────────────────────────────────────┐
│ Engine → Console: log messages (severity + text) │
│ Console → Engine: user commands (text strings) │
│ │
│ SimpleConsole: thread-safe (mutex-protected) │
│ Command registry: handler + description + category + │
│ usage + permission level │
│ Permission: Player → Moderator → Admin → Developer │
└─────────────────────────────────────────────────────────┘
Key files:
-
SparkConsole/src/main.cpp— Console entry point -
SparkConsole/src/ConsoleApp.cpp— Main loop and pipe I/O -
SparkEngine/Source/Utils/ConsoleProcessManager.h— Engine-side pipe management -
SparkEngine/Source/Utils/SparkConsole.h— Log sink and command registry
Published from 2b03dc797148. Edit the canonical source in wiki/.
- Documentation
- Docs route
- Wiki index
- Guides
- Tutorials
- Samples
- Examples
- API Reference
- API route
- Reference
- Build Guide
- Dependencies
- FAQ
- Changelog
- Roadmap
- Contributing
- Code of Conduct
- Home
- FAQ
- Getting Started
- Quick-Start Tutorial
- Making Your First Game
- Making Your First Multiplayer Game
- Artist Workflow Guide
- Editor Walkthrough
- Migration Guide
- How SparkEngine Works
- Architecture Overview
- Engine Architecture Flowchart
- Creating a Game Module
- Game Modules (catalog)
- Entity Component System
- Rendering and Graphics
- Physics
- Cloth Simulation
- Audio
- Input System
- Camera System
- Scripting with AngelScript
- Visual Scripting
- AI and Navigation
- Animation
- 2D Systems
- Networking
- Dedicated Server
- Multiplayer Quick Start
- Area Server Architecture
- Scene Management
- Large World Support
- Collaborative Editing
- Coroutine System
- Event System
- Event Response System
- Job System
- UI System
- UI Layout Extensions
- Localization
- Dialogue System
- Destruction System
- Replay System
- Achievement System
- Loading System
- Mod System
- Content Delivery
- Tween System
- Memory Integrity
- Gameplay Systems
- Terrain and Procedural Generation
- Save System
- Persistence System
- Day Night Cycle and Weather
- Cinematic Sequencer
- Runtime Prefabs
- SparkEditor
- Editor Tutorials
- SparkConsole
- SparkDaemon
- Shader Pipeline
- Asset Pipeline
- Asset Validation
- Asset Migration
- Game Packaging
- Online Services
- DataTable System
- Loot and Crafting System
- CSG System
- Font System
- Timer Manager
- Movie Render Pipeline
- HLOD and World Partition
- Remote Debug System
- Selection Manager
- Asset Dependency Graph
- Editor Automation
- File Watcher
- Project Templates
- System Requirements
- VR Support
- Mobile Platform
- Accessibility
- Platform Input
- Platform Certification
- Cross-Compilation: Wine Testing
- RHI Abstraction Layer
- D3D11 Backend
- D3D12 Backend
- Vulkan Backend
- OpenGL Backend
- Metal Backend
- DXR Raytracing
- Hybrid Ray Tracing
- Upscaling (DLSS/FSR)
- Render Graph
- Shader Graph
- GPU Particles
- GPU-Driven Rendering
- Volumetric Fog
- Volumetric Clouds
- Global Illumination
- Virtual Texturing
- Water Rendering
- Clustered Lighting
- Material System
- Post-Processing
- Shadow System
- Particle System
- Decal System
- Sky and Atmosphere
- Foliage System
- Mesh Shaders
- Neural Rendering
- Configuration Reference
- Performance Tips
- Benchmark Framework
- Threading Model
- Fuzz Policy and Parser Security
- Memory Safety
- Memory Management Patterns
- Build System and CMake Modules
- Profiler and Debugging
- Performance Profiling Guide
- Telemetry System
- Crash Reporting
- Golden Image Testing
- Utilities
- Testing
- Fuzz Policy and Parser Security
- Codebase Statistics
- Codebase Health
- Error Handling Patterns
- Hot Reload Overview
- Troubleshooting
- Contributing
- Workflow Patterns
- Build Optimizations
- CI Reproducible Builds
- GitHub API and PR Checks
- Git Rebase Conflicts
- Clang-Format
- Code Quality Violations
- AI Bloat Pattern
- MinGW + Wine Cross-Compilation
- Live Editor Testing
- Engine & Renderer Landscape
- DuetOS Portability Catalog
- Five-Engine Analysis
- Eleven-Engine Analysis
- ThorVG / Unity Graphics Analysis
- Advanced Techniques Catalog
- Third-Party Library Evaluation
- Engine Viability Evaluation
- Engine Feature Recommendations
- Project Recommendations
- Mac Compatibility Analysis
- Codebase Observations
- Codebase Bloat Audit
- Test Suite Audit
- Documentation Coverage Audit
- ThirdParty Dependencies Audit
- Load Test Baseline
- Gameplay Systems Status
- SparkGame Module Status
- Stub and Abandoned Features
- Memory Integrity System
- Memory Safety Evaluation
- Hardware Acceleration Systems
- Jolt Physics Integration
- GPU/CPU Separation Plan
- Daemon Services Architecture
- Reflection & Polymorphism Refactoring Plan
- SparkBuild In-Tree
- Wine No-JobSystem Breakthrough
- Wine Role and Fallback Tiers