Skip to content

UI System

MichaelFisher1997 edited this page Jan 5, 2026 · 1 revision

UI System

Immediate-mode 2D user interface rendering with bitmap fonts and basic widgets.


Overview

The UI system provides:

  • Orthographic 2D rendering
  • Bitmap font text rendering
  • Pre-built widgets (buttons, text inputs)
  • Menu screen rendering

UISystem

File: src/engine/ui/ui_system.zig

Structure

pub const UISystem = struct {
    renderer: rhi.RHI,
    screen_width: f32,
    screen_height: f32,
};

Render Lifecycle

ui.begin();          // Setup orthographic projection
  ui.drawRect(...);  // Draw elements
  ui.drawText(...);  // Render text
ui.end();            // Flush UI batch

Drawing Methods

Method Description
drawRect(rect, color) Filled rectangle
drawTexture(texture_id, rect) Textured quad
drawRectOutline(rect, color, thickness) Rectangle border
resize(width, height) Update dimensions

Types

pub const Color = rhi.Color;  // RGBA float
pub const Rect = rhi.Rect;    // x, y, width, height

Font Rendering

File: src/engine/ui/font.zig

Bitmap font rendering using hardcoded 5x7 pixel glyphs.

Available Characters

  • Letters: A-Z (uppercase, lowercase converted)
  • Digits: 0-9
  • Special: Space, hyphen, colon, period

Rendering Algorithm

Each glyph rendered as individual rectangles:

for each row (0..7):
    for each col (0..5):
        if bit is set:
            drawRect(x + col*scale, y + row*scale, scale, scale, color)

Font Functions

Function Description
drawGlyph(ui, glyph, x, y, scale, color) Single character
drawText(ui, text, x, y, scale, color) String (left-aligned)
drawTextCentered(ui, text, cx, y, scale, color) Center-aligned
measureTextWidth(text, scale) Calculate pixel width
drawNumber(ui, num, x, y, color) Integer value

Example

// Draw title centered at top
font.drawTextCentered(ui, "ZIGCRAFT", screen_w / 2, 50, 4.0, Color.white);

// Draw FPS in corner
font.drawText(ui, "FPS:", 10, 10, 2.0, Color.green);
font.drawNumber(ui, @intFromFloat(fps), 60, 10, Color.green);

Widgets

File: src/engine/ui/widgets.zig

Pre-built UI components for menus and forms.

Button

pub fn drawButton(
    ui: *UISystem,
    rect: Rect,
    label: []const u8,
    scale: f32,
    mx: f32, my: f32,  // Mouse position
    clicked: bool,     // Mouse click state
) bool  // Returns true if clicked

Visual States:

State Background Border
Normal Dark (rgba(0.13, 0.17, 0.24, 0.92)) Gray
Hover Light (rgba(0.2, 0.26, 0.36, 0.95)) White

Text Input

pub fn drawTextInput(
    ui: *UISystem,
    rect: Rect,
    text: []const u8,
    placeholder: []const u8,
    scale: f32,
    focused: bool,
    caret_visible: bool,
)

Features:

  • Dark input field background
  • Placeholder text (gray) when empty
  • Blinking caret when focused
  • Border highlight on focus

Menu System

File: src/game/menus.zig

MenuContext

Passed to all menu draw functions:

pub const MenuContext = struct {
    ui: *UISystem,
    input: *const Input,
    screen_w: f32,
    screen_h: f32,
    time: *const Time,
    allocator: Allocator,
    window_manager: ?*WindowManager,
};

Menu Screens

Home Screen

drawHome(ctx, state) → MenuAction
  • Title: "ZIG VOXEL ENGINE"
  • Buttons: SINGLEPLAYER, SETTINGS, QUIT
  • UI scales based on screen height

Settings Screen

drawSettings(ctx, settings, state, rhi) → MenuAction
Setting Type Range
Resolution Dropdown 720p - 4K
Render Distance +/- 4 - 32 chunks
Mouse Sensitivity +/- 10 - 200
FOV +/- 30 - 120
VSync Toggle On/Off
Shadow Quality Dropdown Low - Ultra
MSAA Dropdown Off - 8X
Anisotropic Dropdown Off - 16X
UI Scale +/- 0.5X - 2.0X
LOD System Toggle On/Off

Create World Screen

drawSingleplayer(ctx, state, seed_input) → MenuAction
  • Seed input field (keyboard handling)
  • RANDOM button for seed generation
  • BACK / CREATE buttons

Hotbar

File: src/game/ui/hotbar.zig

Bottom-of-screen item selection.

Configuration

Setting Default Description
slot_size 44 Slot dimensions
slot_padding 4 Gap between slots
bottom_margin 10 Distance from screen bottom
border_thickness 2 Slot border width
icon_margin 6 Block icon inset

Visual Elements

  • 9 slots centered horizontally
  • Selected slot: light background, white border
  • Block color fill as item icon
  • Slot numbers (1-9) in corner
  • Stack count if > 1

Inventory UI

File: src/game/ui/inventory_ui.zig

Full-screen inventory overlay with drag-and-drop.

Layout

┌─────────────────────────────────────┐
│           INVENTORY                  │
├─────────────────────────────────────┤
│  ┌───┬───┬───┬───┬───┬───┬───┬───┬───┐  │
│  │   │   │   │   │   │   │   │   │   │  │  Row 1 (slots 9-17)
│  ├───┼───┼───┼───┼───┼───┼───┼───┼───┤  │
│  │   │   │   │   │   │   │   │   │   │  │  Row 2 (slots 18-26)
│  ├───┼───┼───┼───┼───┼───┼───┼───┼───┤  │
│  │   │   │   │   │   │   │   │   │   │  │  Row 3 (slots 27-35)
│  └───┴───┴───┴───┴───┴───┴───┴───┴───┘  │
├─────────────────────────────────────┤
│  ┌───┬───┬───┬───┬───┬───┬───┬───┬───┐  │
│  │ 1 │ 2 │ 3 │ 4 │ 5 │ 6 │ 7 │ 8 │ 9 │  │  Hotbar (slots 0-8)
│  └───┴───┴───┴───┴───┴───┴───┴───┴───┘  │
├─────────────────────────────────────┤
│     [DAWN] [NOON] [DUSK] [NIGHT]     │  Time controls
└─────────────────────────────────────┘

Drag and Drop

Action Result
Click empty slot (holding item) Place item
Click occupied slot (holding item) Swap items
Click occupied slot (empty cursor) Pick up item

Time Controls

Button Time Value
DAWN 0.0
NOON 0.25
DUSK 0.5
NIGHT 0.75

Color Constants

pub const Color = struct {
    pub const white = Color{ .r = 1, .g = 1, .b = 1, .a = 1 };
    pub const black = Color{ .r = 0, .g = 0, .b = 0, .a = 1 };
    pub const red = Color{ .r = 1, .g = 0, .b = 0, .a = 1 };
    pub const green = Color{ .r = 0, .g = 1, .b = 0, .a = 1 };
    pub const blue = Color{ .r = 0, .g = 0, .b = 1, .a = 1 };
    pub const transparent = Color{ .r = 0, .g = 0, .b = 0, .a = 0 };
};

See Also


Source: src/engine/ui/, src/game/ui/ | Last updated: January 2026

Clone this wiki locally