Rendering System
The rendering system is built around the CPixmap class,
which wraps DirectDraw surface management. On non-Windows platforms, Free Direct
provides SDL3-based implementations of the DirectDraw API.
CPixmap Overview
Header: include/pixmap.hpp
Source: src/pixmap.cpp (~1,922 lines)
CPixmap is the image surface manager. It allocates and manages
15 DirectDraw surfaces (one per channel), handles sprite blitting, and manages
the display pipeline.
Resolution
The game renders at a fixed 640×480 pixel resolution:
| Constant | Value | Description |
|---|---|---|
LXIMAGE | 640 | Game window width (pixels) |
LYIMAGE | 480 | Game window height (pixels) |
POSDRAWX | 0 | Draw origin X |
POSDRAWY | 0 | Draw origin Y |
Image Channel System
CPixmap manages 15 independent render channels, each backed by a separate DirectDraw surface. Content is rendered into these channels and composited to produce the final frame.
| Channel | Value | Content | Image File |
|---|---|---|---|
CHBACK | 0 | Background terrain | decor000–031.blp |
CHOBJECT | 1 | Foreground objects and pickups | object.blp |
CHBLUPI | 2 | Default player character | blupi000.blp |
CHDECOR | 3 | Decorative overlays | decor000–031.blp |
CHBUTTON | 4 | UI buttons | button.blp |
CHJAUGE | 5 | Gauge bar sprites | jauge.blp |
CHTEXT | 6 | Normal text characters | text.blp |
CHLITTLE | 7 | Small text characters | littletxt.blp |
CHMAP | 8 | Minimap sprites | map.blp |
CHEXPLO | 9 | Explosion sprites | explo.blp |
CHELEMENT | 10 | Particle/element effects | element.blp |
CHBLUPI1 | 11 | Player variant 1 (multiplayer) | blupi001.blp |
CHBLUPI2 | 12 | Player variant 2 (multiplayer) | blupi002.blp |
CHBLUPI3 | 13 | Player variant 3 (multiplayer) | blupi003.blp |
CHTEMP | 14 | Temporary scratch surface | — |
Sprite Dimensions
| Sprite Type | Width | Height | Constants |
|---|---|---|---|
| Objects (enemies, items, vehicles) | 64 px | 64 px | DIMOBJX, DIMOBJY |
| Player character (Blupi) | 60 px | 60 px | DIMBLUPIX, DIMBLUPIY |
| Explosions | 128 px | 128 px | DIMEXPLOX, DIMEXPLOY |
| UI Buttons | 40 px | 40 px | DIMBUTTONX, DIMBUTTONY |
| Gauge bars | 124 px | 22 px | DIMJAUGEX, DIMJAUGEY |
| Normal text characters | 16 px max | 16 px max | DIMTEXTX, DIMTEXTY |
| Small text characters | 16 px max | 12 px max | DIMLITTLEX, DIMLITTLEY |
Render Pipeline
Each game tick, the rendering sequence is approximately:
CDecor::Build(rect)is called to render the game world- Terrain cells in the visible area are blitted from
CHBACK - Moving objects are drawn from
CHOBJECT,CHEXPLO, etc. - Player character is drawn from
CHBLUPI - Decorative overlays from
CHDECORare applied - UI elements (buttons, gauges, text) from
CHBUTTON,CHJAUGE,CHTEXT,CHLITTLE - Minimap drawn from
CHMAP - Final composited frame blitted from backbuffer to primary surface
CPixmap::Display()presents the frame
Camera Scrolling
The camera scrolls to follow the player. Scrolling is triggered when the player approaches the screen edge:
| Constant | Value | Description |
|---|---|---|
SCROLL_SPEED | 8 | Camera scroll speed (pixels per tick) |
SCROLL_MARGX | 80 | Horizontal scroll trigger margin (pixels from edge) |
SCROLL_MARGY | 40 | Vertical scroll trigger margin (pixels from edge) |
Color Depth Modes
The game supports both 8-bit palette and 16-bit true-color rendering,
selected via the TrueColorBack and TrueColorDecor
settings in config.def:
- 8-bit mode — uses
gamefiles/IMAGE08/assets - 16-bit mode — uses
gamefiles/IMAGE16/assets (default) jauge.blpandmap.blpare always loaded from IMAGE08 (no 16-bit version)
Known Rendering Issues
CPixmap::Create() is called twice during startup — once directly,
and once inside CPixmap::CacheAll(TRUE, …). This is a likely
decompilation artifact. Real DirectDraw may reject the second initialization.
See Known Issues.
bTrueColorBack and bTrueColorDecor parameters
appear to be swapped between the declaration in pixmap.hpp and
the definition in pixmap.cpp. This may produce incorrect behavior
when the two color depth settings differ.