-
Notifications
You must be signed in to change notification settings - Fork 0
Architecture
MichaelFisher1997 edited this page Jan 5, 2026
·
1 revision
ZigCraft is a high-performance voxel engine built with Zig and Vulkan. This document provides an overview of the engine's architecture and module organization.
┌─────────────────────────────────────────────────────────────────────────┐
│ Application │
│ (src/game/app.zig) │
├─────────────────────────────────────────────────────────────────────────┤
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ Player │ │ Inventory │ │ Menus │ │ Map Ctrl │ │
│ └─────────────┘ └─────────────┘ └─────────────┘ └─────────────┘ │
├─────────────────────────────────────────────────────────────────────────┤
│ World System │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ World │ │ Chunks │ │ WorldGen │ │ LOD Manager │ │
│ └─────────────┘ └─────────────┘ └─────────────┘ └─────────────┘ │
├─────────────────────────────────────────────────────────────────────────┤
│ Engine Core │
│ ┌───────────────────────────────┐ ┌───────────────────────────────┐ │
│ │ Graphics │ │ Core │ │
│ │ ┌─────┐ ┌─────┐ ┌─────────┐ │ │ ┌─────┐ ┌─────┐ ┌──────────┐│ │
│ │ │ RHI │ │Cam │ │RenderGr.│ │ │ │Time │ │ Log │ │JobSystem ││ │
│ │ └─────┘ └─────┘ └─────────┘ │ │ └─────┘ └─────┘ └──────────┘│ │
│ └───────────────────────────────┘ └───────────────────────────────┘ │
│ ┌───────────────────────────────┐ ┌───────────────────────────────┐ │
│ │ Math │ │ UI │ │
│ │ Vec3, Mat4, AABB, Frustum │ │ UISystem, Font, Widgets │ │
│ └───────────────────────────────┘ └───────────────────────────────┘ │
├─────────────────────────────────────────────────────────────────────────┤
│ Platform (SDL3 + Vulkan) │
└─────────────────────────────────────────────────────────────────────────┘
src/
├── main.zig # Entry point
├── c.zig # Central C interop (@cImport for SDL3, Vulkan)
├── tests.zig # Unit test suite
│
├── engine/ # Core engine systems
│ ├── core/ # Fundamentals
│ │ ├── window.zig # SDL3 window management
│ │ ├── time.zig # Delta time, fixed timestep, FPS
│ │ ├── log.zig # Logging system
│ │ ├── job_system.zig# Thread pool for async work
│ │ ├── ring_buffer.zig# FIFO queue utility
│ │ └── interfaces.zig # Core interface definitions
│ │
│ ├── graphics/ # Rendering
│ │ ├── rhi.zig # Render Hardware Interface (abstract)
│ │ ├── rhi_vulkan.zig# Vulkan backend implementation
│ │ ├── camera.zig # FPS camera with mouse look
│ │ ├── csm.zig # Cascaded Shadow Maps
│ │ ├── render_graph.zig # Pass orchestration
│ │ ├── render_device.zig # GPU resource manager
│ │ ├── texture.zig # Texture wrapper
│ │ └── texture_atlas.zig # Block texture atlas
│ │
│ ├── math/ # Mathematics (wrappers for libs/zig-math)
│ │ ├── vec3.zig # 3D vector
│ │ ├── mat4.zig # 4x4 matrix
│ │ ├── aabb.zig # Axis-aligned bounding box
│ │ ├── frustum.zig # View frustum culling
│ │ └── ray.zig # Ray casting, DDA traversal
│ │
│ ├── physics/
│ │ └── collision.zig # AABB collision detection
│ │
│ ├── input/
│ │ └── input.zig # Keyboard/mouse input polling
│ │
│ └── ui/
│ ├── ui_system.zig # Immediate-mode UI
│ ├── font.zig # Bitmap font rendering
│ └── widgets.zig # Button, text input widgets
│
├── world/ # Voxel world
│ ├── block.zig # Block types and properties
│ ├── chunk.zig # 16x256x16 chunk data structure
│ ├── chunk_mesh.zig # Greedy mesh generation
│ ├── chunk_allocator.zig # GPU megabuffer allocator
│ ├── world.zig # World manager
│ ├── lod_manager.zig # LOD system orchestrator
│ ├── lod_chunk.zig # LOD data structures
│ ├── lod_mesh.zig # LOD mesh generation
│ │
│ └── worldgen/ # Terrain generation
│ ├── generator.zig # Main generator (5-phase pipeline)
│ ├── biome.zig # Biome definitions and selection
│ ├── noise.zig # Noise utilities
│ ├── caves.zig # Cave carving algorithms
│ ├── decorations.zig # Trees, flowers, ores
│ ├── region.zig # Region composition system
│ ├── gen_region.zig# Generation regions
│ ├── world_class.zig # LOD-invariant classification
│ ├── world_map.zig # Minimap rendering
│ └── mood.zig # Region mood system
│
└── game/ # Game logic
├── app.zig # Main application controller
├── state.zig # App state + settings persistence
├── player.zig # Player physics and controls
├── inventory.zig # Item storage system
├── menus.zig # Menu screen rendering
├── hand_renderer.zig # First-person held block
├── block_outline.zig # Target block wireframe
├── map_controller.zig# World map overlay
├── seed.zig # Seed generation utilities
│
└── ui/
├── hotbar.zig # Bottom hotbar widget
└── inventory_ui.zig # Full inventory overlay
libs/ # Local dependencies
├── zig-math/ # Vec3, Mat4, AABB, Frustum
└── zig-noise/ # Perlin, Simplex, fBm noise
assets/
└── shaders/
└── vulkan/ # SPIR-V compiled shaders
The engine uses an abstract RHI layer that decouples rendering code from Vulkan specifics:
// rhi.zig defines the interface
pub const RHI = struct {
vtable: *const VTable,
// ...
};
// rhi_vulkan.zig implements it
pub fn createVulkanRHI(...) RHI { ... }Benefits:
- Clean separation of concerns
- Potential for multiple backends (though currently Vulkan-only)
- Testable rendering logic
GPU resources use opaque u32 handles instead of pointers:
pub const BufferHandle = u32;
pub const TextureHandle = u32;
pub const ShaderHandle = u32;Benefits:
- Safe resource lifetime management
- Easy serialization
- Deferred deletion without dangling pointers
Heavy work is offloaded to background threads:
| Pool | Threads | Purpose |
|---|---|---|
gen_pool |
4 | Terrain generation |
mesh_pool |
3 | Chunk mesh building |
lod_gen_pool |
3 | LOD generation/meshing |
Jobs use priority queues sorted by distance to player.
To prevent floating-point precision issues at large world coordinates:
// Camera stays at origin, world moves around it
fn getViewMatrixOriginCentered() Mat4 {
return Mat4.lookAt(Vec3.zero, forward, up);
}
// Chunks rendered with relative positions
chunk_world_pos = chunk_pos - camera_pos;1. Input.pollEvents() # Process SDL events
2. Time.update() # Calculate delta time
3. Player.update(input, dt) # Physics, collision
4. World.update(player_pos) # Queue/unload chunks
5. RHI.beginFrame() # Acquire swapchain image
6. RenderGraph.execute() # Shadow + main passes
7. UI.render() # Menus, HUD
8. RHI.endFrame() # Submit + present
Missing → Generating → Generated → Meshing → MeshReady → Uploading → Renderable
↓ ↓ ↓ ↓ ↓ ↓
JobQueue GenWorker State MeshWorker RingBuffer MainThread
| Thread | Responsibilities |
|---|---|
| Main | Input, rendering, GPU uploads, game logic |
| Gen Workers (4) | Terrain generation (CPU-bound) |
| Mesh Workers (3) | Greedy meshing (CPU-bound) |
| LOD Workers (3) | LOD generation and meshing |
Synchronization:
-
RwLockon chunk map (shared reads, exclusive writes) -
Mutexon job queues and mesh data - Atomic
pin_countprevents chunk unloading during async work
Functions accept std.mem.Allocator explicitly:
pub fn init(allocator: Allocator, ...) !*Self {
const self = try allocator.create(Self);
errdefer allocator.destroy(self);
// ...
}The GlobalVertexAllocator manages a single 4GB megabuffer:
- Best-fit allocation from free-list
- Automatic coalescing on free
- Single buffer binding for all chunks
- Engine Core - Window, time, logging, job system
- Rendering - RHI, camera, shadows, render graph
- World System - Chunks, meshing, LOD
- World Generation - Terrain, biomes, caves
Source: Project structure and design documents | Last updated: January 2026