A window: a layer that does not scroll

The map moves and this does not, which the map alone cannot express. The
scroll registers move ALL of it, so a score printed into the map slides
away, and one printed into whichever rows the view happens to be showing
jumps a pixel at a time as the fine offset changes.

Port 0x3D is how many rows tall and 0x3E is which row it starts at. Nought
tall is no window, so a cleared screen has none and every program written
before this means what it meant. A start row is a register because a
status bar along the bottom is as common as one along the top.

IT HAS ITS OWN MEMORY, and that is the argument for it. The cheaper design
draws the top rows of the MAP without the scroll applied - no new memory,
one register - and makes those rows part of the playfield's ring, so a
game that scrolls vertically has to route its world around its own
scoreboard for ever. The point of a status bar is that it is not somewhere
in the level. Lunar Porter does not scroll vertically today and will the
moment an orbit is a thing you can reach.

0xC000 in the screen bank, which the map does not reach: it ends at
0xBFFF. Same cells, same tiles, same pages, same schemes. Being in the
screen bank makes it per screen, so flipping the buffer flips the status
bar with it - what a double buffered game wants, and surprising the other
way round.

Drawn over everything, sprites included. A sprite that could cover the
fuel gauge would be a bug in every game that had both.

Tile modes only. In bitmap mode the picture is using that memory, so a
bitmap program pins things to the screen with sprites, which are in screen
coordinates for the same reason.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01E2JrLzFvuFX9fgi1LDRjrW
This commit is contained in:
Anachronaut
2026-09-03 00:19:09 -04:00
co-authored by Claude Opus 5
parent e3eccd17a8
commit 17c8da111f
4 changed files with 194 additions and 0 deletions
+34
View File
@@ -257,6 +257,40 @@
#define VIDEO_PALETTE_BYTES 4
#define VIDEO_PALETTE_SIZE 256
// ---- The window: a layer that does not scroll ----
//
// A status bar over a playfield. The map moves and this does not, which the map alone cannot
// express: the scroll registers move ALL of it, so a score printed into the map is a score
// that slides away, and one printed into the rows the view happens to be showing is one that
// jumps a pixel at a time as the fine offset changes.
//
// ITS OWN MEMORY, and that is the whole argument. The first design drew the top rows of the
// MAP without the scroll applied, which needs no new memory and costs one register - and
// makes those rows part of the playfield's ring, so a game that scrolls vertically has to
// route its world around its own scoreboard for ever. The whole point of a status bar is that
// it is not somewhere in the level.
//
// 0xC000 to 0xFFFF in the screen bank, which the map does not reach: it ends at 0xBFFF. Sixty
// four rows of the same 256 byte cells, so a window row is a page like a map row is, and a
// cell in it means exactly what a cell in the map means - same tiles, same pages, same
// colour schemes.
//
// PER SCREEN, because it is in the screen bank: flipping to the other buffer flips the status
// bar with it, which is what a double buffered game wants and would be surprising the other
// way round.
#define VIDEO_WINDOW_BASE 0xC000
#define VIDEO_WINDOW_ROWS 64
// How many screen rows tall it is, and which screen row it starts at. NOUGHT IS OFF, so a
// machine that wakes up with a cleared screen has no window and every program written before
// this one means what it meant.
//
// A start row is worth a register because a status bar at the bottom is as common as one at
// the top, and working it out from the screen height is a thing every program would have to
// do again.
#define VIDEO_WINDOW_HEIGHT 0x3D
#define VIDEO_WINDOW_AT 0x3E
// ---- Modes ----
//
// Both are 8x8 cells over the same engine; only how many of them differ. The pixel count