2026-07-18 20:43:18 +02:00
2026-07-18 20:34:55 +02:00
2026-07-18 20:34:55 +02:00
2026-07-18 20:34:55 +02:00
2026-07-18 20:34:55 +02:00
2026-07-18 20:43:18 +02:00
2026-07-18 20:34:55 +02:00
2026-07-18 20:43:18 +02:00
2026-07-18 20:43:18 +02:00
2026-07-18 20:43:18 +02:00

C64 Demo — Teletype Games slide show (Oscar64)

A Commodore 64 slide show written in C, built with the Oscar64 compiler. A port of the c64-demo originally written in 6502 assembly (ACME): five slides rotate automatically with per-slide transitions through black, and the show can also be driven from the keyboard.

The slides

  1. TTG logo + credits scroller — giant TTG letters built from 8×8 bitmaps with a gold color wash running across them, a pulsing TELETYPE GAMES title, and a smooth pixel scroller with the crew credits.
  2. Our first gameDEFINITELY NOT AN IMPOSTOR in big 3×5 block letters with the gold wash, "introduced on TIC-80".
  3. Our second gameIS COMING in big letters with a drop shadow; raster bars run on the border only, so the text stays readable.
  4. Contact — pulsing big CONTACT title, web / BBS / IRC lines, a 12-cell three-layer parallax starfield, and six hardware sprites (four-pointed stars) floating on sine-wave paths behind the text.
  5. The assembly confession — a justified-text piece about how this slide show was written with a little help from an AI; the body types in live (one character per frame with a white block cursor), and a closing line appears and pulses when the typing is done.

Each slide is shown for 8 seconds (SLIDE_TIME in src/defs.h, PAL frames); slide 5 gets 9 seconds (S5_TIME) to let the typewriter finish.

Controls

Key Action
SPACE next slide immediately
INST/DEL (backspace) previous slide
P pause toggle — the countdown freezes and a white P marker appears in the top-right corner; effects keep running, and SPACE/DEL still work while paused
M mute/unmute — toggles the SID music on or off

Keys are read directly from the CIA1 keyboard matrix (the KERNAL IRQ is disabled).

Build and run

make build       # compile -> build/demo.prg (builds the compiler too on first run)
make run         # build + launch in VICE (requires x64sc)
make rebuildrun  # clean rebuild + run
make clean       # remove the build directory
make deps        # on macOS: install VICE via Homebrew

The same targets are available as VS Code tasks from .vscode/tasks.json (build is the default build task).

Loading the .prg on a real or emulated C64:

LOAD"*",8,1
RUN

Source layout

File Contents
src/main.c main loop, slide sequencer, keyboard scanning (SPACE / DEL / P / M), slide tables
src/defs.h hardware pointers, colors, layout/timing constants, the screen-code charmap
src/transitions.c slide transition engine: show/hide, three transition types (fade, dissolve, wipe), wait_frame raster sync, color snapshot
src/common.c shared routines (clear_screen, print_text, draw_big), shared tables (row×40 lookup, 3×5 block font, wash/pulse/fade color ramps)
src/music.c SID music driver: three-voice pattern player (bass, drums, echo lead) with the note/pattern tables of the Impostor tune
src/slide1.cslide5.c one file per slide: sN_init (draws the screen), sN_update (runs once per frame), plus slide-local data

The translation units are tied together by Oscar64's #pragma compile("file.c") mechanism: every header pulls in its matching .c file, so make only needs to pass src/main.c to the compiler.

How it works

Slide framework

Every slide consists of an init routine (draws the whole screen), an update routine (called once per frame, runs exactly one frame) and a duration in frames. The main loop in main.c calls the current update, counts the frames down, and steps to the next slide when time runs out — or immediately on SPACE/DEL.

Timing

There are no interrupts: the code polls the raster register ($D012, vic.raster) and does all screen updates while the beam is in the lower border (RAS_BOTTOM). Slide 1 additionally splits the frame mid-screen to enable horizontal fine scrolling (vic.ctrl2) for the scroller row only; slide 3 chases the beam down the frame, recoloring the border every 4 lines to draw the raster bars.

Transitions

Each slide has its own in-transition and out-transition, chosen from three types via tin_tbl / tout_tbl in main.c:

  • Fade — steps every color RAM cell through fadetbl (each color → one shade darker; every chain hits black within 4 steps). The new slide is drawn with the display off, its colors are snapshotted to the buffer at $C000 and blanked, then the fade-in walks each cell back up to its snapshot color.
  • Dissolve — a 10-bit Galois LFSR (period 1023) visits every screen cell exactly once in pseudo-random order. 25 cells per frame = 40-frame (~0.8 s) full reveal.
  • Wipe — column-by-column sweep from left to right, one column per frame.

All transitions start with a short white-to-grey border flash.

Music

src/music.c is a three-voice SID pattern player; the tune is track 0 ("room work") of the Impostor TIC-80 cart, converted by hand into a 128-row pattern grid (bass: 50% pulse, drums: noise, echo canon: decaying triangle pluck 3 octaves up, delayed by 2 rows). Rows are one byte per voice: $00 = nothing, $01 = key off, $80|n = play note n. music_play is ticked once per frame: from the main loop and from wait_frame, so the music keeps playing through transitions.

Memory map

$0801 .. ...     BASIC stub + machine code (Oscar64 defaults)
$0340 .. $037E   sprite shape (cassette buffer, 64-aligned)
$0400 .. $07E7   screen RAM (written directly)
$C000 .. $C3E7   color RAM snapshot buffer for transitions
$D000 .. $D02E   VIC-II registers (display, sprites, raster)
$D400 .. $D418   SID registers (music)
$D800 ..         color RAM
$DC00 / $DC01    CIA1 keyboard matrix

Differences from the original

  • Texts are converted to screen codes at compile time via #pragma charmap(97, 1, 26), so plain C string literals can be written straight to the screen.
  • Self-modifying vectors and zero-page pointers are replaced by function pointers and ordinary C array indexing; the behavior (timing, effects, music) is unchanged.
  • Compiled with -n -O2 (fully native 6502 code) so the raster-polling parts are fast enough to fit in the frame.
S
Description
No description provided
Readme
1.1 MiB
Languages
C++ 84.3%
C 13.8%
Assembly 1.2%
Batchfile 0.2%
Makefile 0.2%
Other 0.1%