Mode X in Turbo Pascal, Part 4: Tilemaps and Streaming
A renderer becomes a game when it can show world-scale structure, not just local effects. That means tilemaps, camera movement, and disciplined data loading. In Mode X-era development, these systems were not optional polish. They were the only way to present rich scenes inside strict memory budgets.
This final Mode X article focuses on operational structure: how to build scenes that scroll smoothly, load predictably, and remain debuggable.
Start with memory budget, not features
Before defining map format, set your memory envelope:
- available conventional/extended memory
- VRAM page layout
- sprite and tile cache size
- IO buffer size
Then derive map chunk dimensions from those limits. Teams that reverse the order usually rewrite their map loader halfway through the project.
Tilemap schema that survives growth
A practical map record often includes:
- tile index grid (primary layer)
- collision flags
- optional overlay/effect layer
- spawn metadata
- trigger markers
Keep versioning in the file header. Old DOS projects often outlived their first map format and paid dearly for “quick binary dumps” with no compatibility markers.
type
TMapHeader = record
Magic: array[0..3] of Char; { 'MAPX' }
Version: Word;
Width, Height: Word; { in tiles }
TileW, TileH: Byte;
LayerCount: Byte;
end;
Version fields are boring until you need to load yesterday’s assets under today’s executable.
Camera math and draw windows
For each frame:
- determine camera pixel position
- convert to tile-space window
- draw only visible tile rectangle plus one-tile margin
The one-tile margin prevents edge pop during sub-tile movement. Combine this with clipped blits from Part 2 and you get stable scrolling without full-map redraw.
Chunked streaming from disk
Large maps should be chunked. Load around camera, evict far chunks, keep hot set warm.
A simple policy works well:
- chunk size fixed (for example 32x32 tiles)
- maintain 3x3 chunk neighborhood around camera chunk
- prefetch movement direction neighbor
This is not overengineering. On slow storage, missing prefetch translates directly into visible hitching.
Keep IO deterministic
Disk access must avoid unpredictable burst behavior during input-critical moments. Two rules help:
- schedule loads at known frame points (post-render or pre-update)
- cap max bytes read per frame under stress
When a chunk is not ready, prefer visual fallback tile over frame stall. Small visual degradation is often less disruptive than control latency spikes.
Practical cache keys
Use integer chunk coordinates as cache keys. String keys are unnecessary overhead in this environment and complicate diagnostics.
type
TChunkKey = record
CX, CY: SmallInt;
end;
Pair keys with explicit state flags: Absent, Loading, Ready, Dirty. State clarity is more important than clever container choice.
HUD and world composition
Render world layers first, then entities, then HUD into same draw page. Keep HUD draw routines independent from camera transforms. Many old engines leaked camera offsets into UI code and carried that bug tax for years.
You can validate this quickly by forcing camera to extreme coordinates and checking whether UI still anchors correctly.
Failure modes to test intentionally
Test these early, not at content freeze:
- camera crossing chunk boundaries repeatedly
- high-speed movement through dense trigger zones
- partial chunk read failure
- map version mismatch
- missing tile index fallback path
Each one should degrade gracefully with explicit logging. Silent corruption is far worse than a visible placeholder tile.
Cross references for full pipeline context
- Part 1: Planar Memory and Pages
- Part 3: Sprites and Palette Cycling
- Turbo Pascal Before the Web
- CONFIG.SYS as Architecture
These pieces together describe not just rendering, but operation: startup profile, page policy, draw order, and asset logistics.
Closing note on Mode X projects
Mode X is often presented as nostalgic low-level craft. It is also a great systems-design classroom. You learn cache boundaries, streaming policies, deterministic updates, and diagnostic overlays in an environment where consequences are immediate.
If this series worked, you now have a path from first pixel to world-scale scene architecture:
- memory model
- primitives
- sprites and timing
- streaming and camera
That sequence is still useful on modern engines. The APIs changed. The discipline did not.
Treat your map format docs as part of runtime code quality. A map pipeline without explicit contracts eventually becomes an incident response problem.