Analysis model: gpt-5.5 xhigh

Crystal Dream by Triton

Crystal Dream is Triton's Swedish July 1992 MS-DOS full demo and the PC demo winner at Hackerence 1992. This analysis uses the original Scene.org cd_trn.zip release.

Tooling note: CRYSTAL.EXE and the executable prefix inside DREAM.DAT are packed. Plain depacking produced plausible sizes but still-obscured code; encrypted PKLITE-style depacking with depklite -d produced usable 16-bit code with VGA ports, DOS/BIOS calls, and the setup strings. Offsets below are decoded payload offsets, not original source labels.

File Layout

The archive contains:

Authenticated file hashes:

54f4f2f804ee37c0fc947b09c633f0362d89d905d9d8674bc39c07167aa9792a  cd_trn.zip
bc9cceca47fc2d41d0382fd2d539b45c7f6aaf06d9050ced199b802fdf17ac11  CRYSTAL.EXE
8e66507c18956ddfc129c1617ab79eba878699194f20327ce65b9d67b3ffdad8  DREAM.DAT
5476fb2b6920ba6c5d67eb6957c2f9450474d60095693d77591907f5184a8d32  README

CRYSTAL.EXE decodes to about 112 KB of useful payload. DREAM.DAT's executable prefix decodes to about 57 KB, and the large overlay remains the main container for pictures, music, object data, compressed image streams, and end-scroller text.

Complete Direct Runtime

The original archive was run in DOSBox-X 2026.01.02 with a normal 386 core, fixed 25000 cycles, 16 MB RAM, XMS enabled, EMS disabled, and every sound device disabled. Option 6, Silence, was selected in the demo's own output menu. No music was enabled, heard, captured, or published. External X11/FFV1 capture recorded the VGA output without relying on the emulator's internal recorder.

The old 183.23-second capture stopped before the raytraced picture sequence and the real ending. This pass followed the original executable through the full effect route and one complete pass of the authored end scroller. Once its opening text repeated, one Escape was injected at that repeat boundary. CRYSTAL.EXE returned to the DOS prompt and the runner closed with status 0. The lossless capture is 684.44 seconds long.

Useful route anchors are:

~00s    Triton / presents / Crystal Dream title sequence
~20s    palette field into the starfield vector show
~70s    flat and glenz object variations
~110s   checkerboard-floor polygon sequence
~176s   complex translucent object and shadow over the floor
~216s   later starfield object sequence
~224s   raytraced reflective-sphere picture
~236s   raytraced textured-cylinder picture
~252s   raytraced sphere arrangements
~288s   starfield end scroller begins
later   complete end text repeats, Escape, DOS prompt

These eight GIFs are continuous excerpts from that one direct silent run. They are not a slideshow assembled from the old four timestamp frames.

Crystal Dream direct title sequence

Crystal Dream direct starfield vector motion

Crystal Dream direct glenz vector motion

Crystal Dream direct checkerboard cube and shadow

Crystal Dream direct translucent checkerboard object

Crystal Dream direct transition into the raytraced picture sequence

Crystal Dream direct textured-cylinder raytrace display

Crystal Dream direct starfield end scroller

The older timestamp stills remain useful as fixed reference points:

Crystal Dream title still

Crystal Dream starfield vector still

Crystal Dream checkerboard polygon still

Crystal Dream later faceted object still

No audio, H.264, or MP4 derivative is published.

High-Level Structure

Crystal Dream is closer to a trackmo than to Cronologia's "one EXE per part" structure. The visible sections are driven by a single runtime plus data/script streams:

  1. Setup and sound-device selection.
  2. VGA mode setup and palette/image loading.
  3. Vector object show.
  4. Flat/glenz polygon drawing.
  5. Raytraced picture display and transitions.
  6. End scroller and credits.
  7. Timer service running throughout, with optional music replay only when a sound output is selected.

The credits in the end scroller match the code layout: vector routines by Vogue, fill routines by Mr. H, music routine by Mr. H, graphics/music by Vogue, objects by Loot/Vogue/Mr. H.

Display Mode Trick

The defining technical choice is mode 0x0d, not normal mode 0x13.

At CRYSTAL_0.dep:0x8202:

mov ax, 000dh
int 10h
mov dx, 03d4h
out dx, 0011h
out dx, 9c12h
out dx, 9c15h
out dx, 8011h

BIOS mode 0x0d gives 320x200 16-color planar memory. The demo then programs VGA registers directly, so it gets the speed properties of EGA-style planar pixels plus VGA palette control.

The common register set is:

03c4h index 02h  ; Sequencer map mask: choose writable plane(s)
03ceh index 00h  ; Graphics Controller set/reset color
03ceh index 01h  ; enable set/reset
03ceh index 03h  ; data rotate/function
03ceh index 05h  ; write/read mode
03ceh index 07h  ; color don't-care / compare support
03ceh index 08h  ; bit mask inside a byte
03d4h index 0ch/0dh ; CRTC display start address
03c8h/03c9h      ; VGA DAC palette
03dah bit 3      ; vertical retrace

Why it matters: one byte in planar mode represents 8 horizontal pixels in one plane. With all planes or selected planes enabled, one store can update a 32-pixel-wide logical group across the 4 bitplanes. That is why the flat polygon routines are unusually fast for a 286-era PC demo.

VGA Image Loader

The image loader at CRYSTAL_0.dep:0x83a6 writes compressed planar picture data into VGA memory plane by plane.

The outer loop selects one plane:

for (plane = 0; plane < 4; plane++) {
    outw(0x3c4, 0x0200 | (1 << plane));

    for (row = 0; row <= 0xc7; row++) {
        dst = row * 0x28;        // 40 bytes per scanline
        decode_one_scanline(dst, dst + 0x28);
    }
}

The scanline stream is a compact RLE:

tag = *src++;

if (tag < 0x80) {
    count = tag + 1;
    while (count--) {
        vram[dst++] = *src++;
    }
} else if (tag > 0x80) {
    count = 0x101 - tag;
    value = *src++;
    while (count--) {
        vram[dst++] = value;
    }
} else {
    // tag == 0x80: no-op/control case
}

Palette loading at CRYSTAL_0.dep:0x8483 writes exactly 16 RGB triplets:

outb(0x3c8, index);
outb(0x3c9, r);
outb(0x3c9, g);
outb(0x3c9, b);

It also stores a copy of the palette at 0x6f4c, which lets fades and restores work without rereading the DAC.

Timing And Page Flip

There are two sync paths.

The simple path at CRYSTAL_0.dep:0x84ab waits for retrace, then writes the CRTC start address:

while (inp(0x3da) & 8) {}
disable_interrupts();
CRTC[0x0c] = start >> 8;
CRTC[0x0d] = start & 255;
enable_interrupts();
while (!(inp(0x3da) & 8)) {}

The timer-assisted path waits on a counter touched by the interrupt handler, then performs the same page-start update. This is used when the music/timer service is active.

The interrupt path at CRYSTAL_0.dep:0xd000 does three jobs:

  1. Sample VGA status timing around 0x3da.
  2. Increment frame/tick counter 0x740c.
  3. Optionally call a drawing callback pointer at 0xfc9a.

Before the callback, it saves Graphics Controller and Sequencer state, switches to a known planar write state, sets ES = A000h, calls the callback, then restores the VGA registers. That lets timed overlay effects run from the IRQ without permanently corrupting the current VGA mode.

Vector Matrix Setup

The matrix builder starts around CRYSTAL_0.dep:0x56e0. It indexes two sine/cosine tables around decoded offsets 0x8714 and 0x8f14.

The three angle words come in through the stack frame. For each angle:

sin_x = sintab[angle_x];
sin_y = sintab[angle_y];
sin_z = sintab[angle_z];
cos_x = costab[angle_x];
cos_y = costab[angle_y];
cos_z = costab[angle_z];

Then it builds a 3x3 rotation matrix into the caller's buffer. The code uses signed imul and takes the high word DX as the fixed-point result:

mov ax, [cos_x]
imul word [cos_z]
mov [matrix+0], dx

A representative matrix term is:

m00 = hi16(cos_x * cos_z) + 2 * hi16(hi16(sin_x * sin_y) * sin_z);
m01 = 2 * hi16(hi16(sin_x * sin_y) * cos_z) - hi16(cos_x * sin_z);
m02 = hi16(cos_y * sin_x);

The exact algebra is arranged to minimize temporary storage: each imul result is immediately accumulated through DX.

Vertex Transform Loop

At CRYSTAL_0.dep:0x57d4, object vertices are transformed until sentinel 0x7fff.

Input is a stream of signed 16-bit triples:

while (true) {
    x = *src++;
    if (x == 0x7fff) break;
    y = *src++;
    z = *src++;

    tx = hi16(x * m00) + hi16(y * m01) + hi16(z * m02);
    ty = hi16(x * m10) + hi16(y * m11) + hi16(z * m12);
    tz = hi16(x * m20) + hi16(y * m21) + hi16(z * m22);

    *dst++ = tx;
    *dst++ = ty;
    *dst++ = tz;
}
*dst++ = 0x7fff;

This is a tight inner loop: no procedure calls inside the vertex body, just lodsw, imul [bp+matrix], add cx,dx, and stosw.

Projection And Clipping

At CRYSTAL_0.dep:0x5847, transformed triples are projected to screen coordinates.

Important globals:

The loop:

while (true) {
    x = src[0];
    if (x == 0x7fff) break;

    z = src[2] + z_bias;
    if (z <= 2) {
        dst_x = 0x7ffe;
        dst_y = 0x7ffe;
        src += 3;
        continue;
    }

    // reject if projected magnitude would overflow/clamp badly
    if (z <= abs(4 * hi16(x * scale))) mark_clipped();
    screen_x = (hi16(x * scale) / z) + 0xa0;

    if (z <= abs(4 * hi16(y * scale))) mark_clipped();
    screen_y = (hi16(y * scale) / z) + 0x64;

    *dst++ = screen_x;
    *dst++ = screen_y;
    src += 3;
}
*dst++ = 0x7fff;

The special value 0x7ffe marks a vertex that exists but is not drawable after clipping.

Polygon Command Interpreter

The polygon dispatcher is at CRYSTAL_0.dep:0x59fc.

It first programs the VGA write mode:

outw(03ceh, ff08h)  ; full bit mask
outw(03ceh, 0b05h)  ; write mode/function setup
outw(03ceh, 0007h)

Then it consumes bytecode commands:

for (;;) {
    cmd = *stream++;
    switch (cmd) {
        case 0x00: draw_quad_or_poly_type_0(); break;
        case 0x03: draw_poly_type_3(); break;
        case 0x12: draw_poly_type_12(); break;
        case 0x06: draw_poly_type_6(); break;
        case 0x02: draw_poly_type_2(); break;
        case 0x10: draw_poly_type_10(); break;
        case 0x11: draw_poly_type_11(); break;
        case 0x01: finish_or_jump(); break;
        case 0x07:
        case 0x08:
        case 0x0a:
        case 0x0b:
        case 0x0d:
        case 0x0e:
        case 0x0f:
            specialized_face_variant();
            break;
    }
}

Command 0x00 at 0x5a9f reads four vertex indexes, looks up projected (x,y) pairs, rejects faces containing 0x7ffe, computes a signed area/cross product, and uses the sign for backface culling.

The culling math is the classic 2D polygon test:

area =
    (x3 - x0) * (y1 - y0)
  - (x1 - x0) * (y3 - y0);

if (area < 0) {
    draw_face();
}

Once accepted, it sets:

03ce index 00h = set/reset color bits
03c4 index 02h = plane mask

and calls the fill routine.

Line Drawer

The line drawer starts at CRYSTAL_0.dep:0x8519.

It is a Bresenham-style planar line routine. Inputs are color/plane and two points. It sets:

outw(03ceh, color << 8 | 00h) ; set/reset
outw(03ceh, 0f01h)            ; enable set/reset on all planes
outw(03ceh, 0003h)            ; write function

Then it decides whether the line is x-major or y-major:

dx = x2 - x1;
dy = y2 - y1;

if (dx < 0) swap endpoints;
if (abs(dy) > abs(dx)) {
    swap_major_axis();
}

Pixel address conversion for mode 0x0d:

byte_offset = y * 0x28 + (x >> 3);
bit_mask = 1 << (7 - (x & 7));
outw(0x3ce, 0x0800 | bit_mask);
vram[byte_offset] |= value;

Horizontal spans are optimized. If the span crosses byte boundaries, it writes a left-edge bitmask, then whole middle bytes with mask 0xff, then a right-edge mask. That is why the code around 0x863b switches the Graphics Controller bit-mask register instead of doing per-pixel branches.

Rectangle/Span Fill

At CRYSTAL_0.dep:0x6d48, a rectangle/span fill routine receives:

It computes:

start_x_byte = (x1 & 0xfff8) >> 3;
end_byte_count = (((x2 & 0xfff8) + 8) - (x1 & 0xfff8)) >> 3;
offset = y1 * 0x28 + start_x_byte;
row_skip = 0x28 - end_byte_count;
height = y2 - y1 + 1;

Then the hot loop is just:

while (height--) {
    memset(vram + offset, 0xff, end_byte_count);
    offset += end_byte_count + row_skip;
}

The color is not in the byte value itself. The byte value is effectively a mask; the selected VGA planes and set/reset registers decide the resulting 4-bit color.

Polygon Fill Edges

The edge setup beginning around CRYSTAL_0.dep:0x6dc7 stores edge endpoints in globals 0xdba8 through 0xdbb4, then computes fixed-point edge slopes with idiv.

The pattern is:

dy = y2 - y1;
dx = x2 - x1;

whole_step = dx / dy;
frac_step = (dx % dy) converted to an unsigned error term;

Negative remainders are normalized by flipping signs and using one's-complement style adjustment:

if (remainder < 0) {
    error_sign = -1;
    quotient--;
    remainder = -remainder;
    frac = ~((0 / dy) result);
}

This gives the filler two edge walkers that can advance left and right x positions per scanline without using division inside the scanline loop.

Dot/Particle Helper

The routine at CRYSTAL_0.dep:0x5480 draws about 0x28 moving points. It accumulates per-point z, multiplies a point by a 3x3 matrix at 0x9894..0x98a4, adds depth bias 0x2328, projects to (x,y), rejects offscreen points, then writes one masked pixel into ES:[byte_offset].

It also appends (address, old_mask) triplets to a small erase list at 0x98a6:

erase_entry.addr = byte_offset;
erase_entry.mask = old_vram_byte & point_mask;
erase_count += 3;

That is the standard "draw sparse points, remember what to restore next frame" optimization.

End Scroller Mode

The decoded DREAM.DAT prefix contains the end-scroller code and text.

At DREAM_0.dep:0x21f7 it briefly sets modes 0x12 and 0x13, then changes CRTC registers manually:

mov ax, 0012h
int 10h
mov ax, 0013h
int 10h

bx = 0x140 >> 3  ; 40-byte logical row
cx = 0x140 >> 2
cx--

CRTC[11h] = 00h
CRTC[01h] = cl
CRTC[13h] = bl
CRTC[17h] = e3h

It also clears bits in CRTC registers 04h and 14h. This is another tweaked VGA layout, using a 320-wide logical row while controlling byte addressing and scanline behavior directly.

At DREAM_0.dep:0x242b, clear/fill is one instruction:

mov cx, 1f40h
rep stosw

0x1f40 is 8000 words, i.e. 16000 bytes. In the selected planar/tweaked mode this is a full fast clear/fill pass for the scroller surface.

End Text Renderer

The text renderer around DREAM_0.dep:0x153a treats each text line as 20-byte records. It first computes line width:

width = 0;
for (i = 1; i <= line_len; i++) {
    c = line[i];
    if (c == 'I' || c == ' ') {
        width += 1;
    } else {
        width += 3;
    }
}
x = (0x28 - width) / 2;

Then it draws characters with a shifting plane mask. The inner write advances the plane mask until it reaches 0x10, then wraps to 0x01 and advances the byte pointer:

mask = 1;
for each source pixel/bit {
    outw(0x3c4, 0x0200 | mask);
    vram[di] = glyph_byte;

    mask <<= 1;
    if (mask == 0x10) {
        mask = 1;
        di++;
    }
}

This matches the 4-plane nature of the display: horizontal character pixels are distributed through plane selection rather than through a linear chunky byte.

The vertical timing loop at DREAM_0.dep:0x14aa waits for retrace high, then low:

while (!(inp(0x3da) & 8)) {}
while ( inp(0x3da) & 8) {}

It advances counters at 0x246a and 0x246b, then calls the scroller update/draw functions.

Music System

The README says the replay supports:

The setup strings in CRYSTAL.EXE expose the same choices and replay rates: 10, 12, 16, 20, 24, 30, 36, and 44 kHz.

The PIT/timer initialization at CRYSTAL_0.dep:0xdb60 reprograms IRQ0:

out 20h, 11h
out 21h, 08h
out 21h, 04h
out 21h, 1fh
out 20h, 20h
out 43h, 36h
out 40h, low(divisor)
out 40h, high(divisor)

The divisor is derived from the selected replay frequency. The code also calibrates against VGA status transitions to derive timing values at 0xfc90, 0xfc92, and 0xfc94.

The mixer core begins around CRYSTAL_0.dep:0xbf32. It is a 4-channel MOD-style mixer. It uses four sample pointers/lengths stored as self-modified words in the code area, reads source bytes, maps them through a volume table at cs:0x272b, and accumulates mixed output in register pairs:

left0  = voltab[*ch0.ptr++];
right0 = voltab[*ch1.ptr++];
left1 += voltab[*ch2.ptr++];
right1 += voltab[*ch3.ptr++];

output(left0, right0, left1, right1);

The output routine is selected by setup:

The Sound Blaster routine polls the DSP busy bit instead of relying on the SB IRQ:

status = inb(base + 0x0c);
if (status & 0x80) {
    busy_counter = 0x40;
} else if (--busy_counter == 0) {
    busy_counter = 0x40;
    dsp_write(0x14);
    dsp_write(0xff);
    dsp_write(0xff);
}

This matches the DOSBox-X compatibility note: Crystal Dream watches the DSP busy cycle from the timer interrupt and restarts playback when the cycle stops. That works on Sound Blaster and Sound Blaster Pro behavior, but fails on SB16-style behavior where the busy cycle does not indicate the same playback-end condition.

The pattern interpreter around CRYSTAL_0.dep:0xc071 advances rows/ticks, wraps pattern positions, processes effect commands like tempo and volume-table selection, and patches channel state used by the mixer. Much of it is intentionally self-modifying: it writes new sample pointer, period, and volume-table addresses directly into the hot mixer code to avoid per-sample indirection.

What Each Visible Section Is Doing

Setup

The setup UI prints device, port, and frequency choices, then stores the selected path in globals used by the timer/mixer. It opens dream.dat, verifies/load-decodes executable and overlay data, initializes the replay, and enters the scripted demo sequence.

Raytraced Picture Sections

Static pictures are stored compressed in DREAM.DAT and expanded into planar VGA memory with the RLE loader. Palette entries are written through 3c8/3c9. Transitions are mostly palette changes, page clears, and timed blits rather than expensive full-screen chunky effects.

Vector Sections

Objects are transformed by the matrix loop, projected by the perspective loop, then consumed by the polygon command interpreter. Backface culling happens before fill. The engine stores projected vertices in a separate buffer so face drawing never needs to redo 3D math.

Glenz/Transparent-Looking Vectors

The transparency-like look comes from planar set/reset and masks, not from alpha blending. Because a byte write can affect selected planes only, the filler can combine plane masks and color bits to produce overlap colors very cheaply. This is the practical payoff of the mode 0x0d plus VGA-register approach.

End Scroller

The end scroller uses a tweaked VGA layout, centered line layout, plane-stepped glyph writes, and a retrace-synchronized update loop. The end text explains the group transition from The Physical Crew to Triton, lists credits, thanks The Space Pigs for information about the undocumented VGA mode, and announces their next demo.

Runtime-To-Code Concordance

The direct motion now covers every visual class rather than four isolated frames:

Shared support under the whole route is the planar VGA mode trick, CRTC page-start update at CRYSTAL_0.dep:0x84ab, and timer/IRQ callback path at 0xd000. With Silence selected, that timing machinery remains active while the optional mixer output does not.

Sources