Skip to content

Architecture

MichaelFisher1997 edited this page Jan 5, 2026 · 1 revision

Architecture

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.


System Overview

┌─────────────────────────────────────────────────────────────────────────┐
│                              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)                        │
└─────────────────────────────────────────────────────────────────────────┘

Directory Structure

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

Key Design Patterns

Render Hardware Interface (RHI)

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

Handle-Based Resources

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

Job System

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.

Floating-Origin Rendering

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;

Data Flow

Frame Update

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

Chunk Lifecycle

Missing → Generating → Generated → Meshing → MeshReady → Uploading → Renderable
    ↓           ↓           ↓          ↓          ↓            ↓
 JobQueue   GenWorker    State    MeshWorker  RingBuffer  MainThread

Threading Model

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:

  • RwLock on chunk map (shared reads, exclusive writes)
  • Mutex on job queues and mesh data
  • Atomic pin_count prevents chunk unloading during async work

Memory Management

Allocator Pattern

Functions accept std.mem.Allocator explicitly:

pub fn init(allocator: Allocator, ...) !*Self {
    const self = try allocator.create(Self);
    errdefer allocator.destroy(self);
    // ...
}

GPU Memory

The GlobalVertexAllocator manages a single 4GB megabuffer:

  • Best-fit allocation from free-list
  • Automatic coalescing on free
  • Single buffer binding for all chunks

See Also


Source: Project structure and design documents | Last updated: January 2026

Clone this wiki locally