Files
2026-07-18 20:43:18 +02:00

144 lines
6.3 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# C64 Demo — Teletype Games slide show (Oscar64)
A Commodore 64 slide show written in C, built with the
[Oscar64](https://github.com/drmortalwombat/oscar64) compiler. A port of the
[c64-demo](../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 game***DEFINITELY NOT AN IMPOSTOR* in big 3×5 block letters
with the gold wash, "introduced on TIC-80".
3. **Our second game***IS 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
```sh
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.c``slide5.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.