-
Notifications
You must be signed in to change notification settings - Fork 0
UI System
MichaelFisher1997 edited this page Jan 5, 2026
·
1 revision
Immediate-mode 2D user interface rendering with bitmap fonts and basic widgets.
The UI system provides:
- Orthographic 2D rendering
- Bitmap font text rendering
- Pre-built widgets (buttons, text inputs)
- Menu screen rendering
File: src/engine/ui/ui_system.zig
pub const UISystem = struct {
renderer: rhi.RHI,
screen_width: f32,
screen_height: f32,
};ui.begin(); // Setup orthographic projection
ui.drawRect(...); // Draw elements
ui.drawText(...); // Render text
ui.end(); // Flush UI batch| Method | Description |
|---|---|
drawRect(rect, color) |
Filled rectangle |
drawTexture(texture_id, rect) |
Textured quad |
drawRectOutline(rect, color, thickness) |
Rectangle border |
resize(width, height) |
Update dimensions |
pub const Color = rhi.Color; // RGBA float
pub const Rect = rhi.Rect; // x, y, width, heightFile: src/engine/ui/font.zig
Bitmap font rendering using hardcoded 5x7 pixel glyphs.
- Letters: A-Z (uppercase, lowercase converted)
- Digits: 0-9
- Special: Space, hyphen, colon, period
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)| 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 |
// 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);File: src/engine/ui/widgets.zig
Pre-built UI components for menus and forms.
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 clickedVisual 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 |
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
File: src/game/menus.zig
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,
};drawHome(ctx, state) → MenuAction- Title: "ZIG VOXEL ENGINE"
- Buttons: SINGLEPLAYER, SETTINGS, QUIT
- UI scales based on screen height
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 |
drawSingleplayer(ctx, state, seed_input) → MenuAction- Seed input field (keyboard handling)
- RANDOM button for seed generation
- BACK / CREATE buttons
File: src/game/ui/hotbar.zig
Bottom-of-screen item selection.
| 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 |
- 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
File: src/game/ui/inventory_ui.zig
Full-screen inventory overlay with drag-and-drop.
┌─────────────────────────────────────┐
│ 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
└─────────────────────────────────────┘
| Action | Result |
|---|---|
| Click empty slot (holding item) | Place item |
| Click occupied slot (holding item) | Swap items |
| Click occupied slot (empty cursor) | Pick up item |
| Button | Time Value |
|---|---|
| DAWN | 0.0 |
| NOON | 0.25 |
| DUSK | 0.5 |
| NIGHT | 0.75 |
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 };
};- Game Systems - Menu navigation
- Input System - UI input handling
Source: src/engine/ui/, src/game/ui/ | Last updated: January 2026