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
+19
View File
@@ -631,6 +631,7 @@ Two rather than one because the two halves of a screen are written at completely
| Atlas | 0xFC00 - 0xFFFF | The palette. 256 entries of four bytes: red, green, blue, and one unused - and tiles 240 to 255 of page 3. |
| Screen | 0x0000 - 0x3FFF | Free in a tile mode. |
| Screen | 0x4000 - 0xBFFF | The map. 128 rows of 256 bytes. |
| Screen | 0xC000 - 0xFFFF | The window. 64 rows of cells that do not scroll. |
| Screen | 0x0000 - 0xF9FF | In bitmap mode, the picture instead: 64,000 bytes, one to a pixel. |
**There are two screen banks and one atlas**, laid out identically, and the device shows one screen at a time. See Two Screens below.
@@ -732,6 +733,22 @@ The buffer belongs to the program. It is not cleared between frames, because a p
`Programs/CosmOS/Apps/Sprite.asm` moves one across the shell's own text without writing a byte of the map.
### The 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 is a score that 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 screen rows tall it is and **0x3E** is which row it starts at. Zero tall is no window, so a cleared screen has none and every program written before it existed 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.
Its cells are at **0xC000 in the screen bank**, 64 rows of 256 bytes, and a cell means exactly what a map cell means - same tiles, same pages, same colour schemes. **A window cell is at a screen position**, where a map cell is at a position in a world the screen is looking at part of; keeping those two coordinate systems apart is the whole of the feature.
**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, which needs no new memory at all - 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.
Being in the screen bank means it is **per screen**: 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.
**It is drawn over everything, sprites included.** A sprite that could cover the fuel gauge would be a bug in every game that had both.
It is a tile-mode layer. In bitmap mode there is nothing to draw it from - the picture is using that memory - so a bitmap program that wants something pinned to the screen uses sprites, which are in screen coordinates for the same reason.
### Cells:
Two bytes. The first says which tile, the second how to colour it.
@@ -763,6 +780,8 @@ Bits 6 and 7 are still reserved and should be left at zero.
| 0x3A | Owns screen 0. Not read or written. |
| 0x3B | Owns screen 1. Not read or written. |
| 0x3C | Display. Which of the two screens is being shown. |
| 0x3D | Window height, in rows. Zero is no window. |
| 0x3E | Window start, which screen row it begins at. |
| Mode | Screen | Cells |
| --- | --- | --- |