Draw into the whole window, not its top-left 320x200
The graphics verbs documented a coordinate transform that did not exist. With SCALE off a coordinate went straight to akgl_draw_* as a pixel address, so an 800x600 window drew a C128 listing into its corner and left the rest unused -- while the chapter said coordinates were 320x200 and stretching to fit was the host's business. akbasic_GraphicsBackend gains a size entry point, require_graphics() asks it before every verb that draws so a resized window is honoured between two statements, and 320x200 becomes the fallback for a backend that leaves it NULL. It is the record's one optional member, so a host written against the old header keeps the behaviour it had. SCALE now maps onto the device, and RGR(1)/RGR(2) report the drawing surface so a program can use a window whose size it did not choose. RGR(0) is BASIC 7.0's own field, the GRAPHIC mode. SCALE also mapped xmax onto the width rather than onto the last pixel, so SCALE 1, 319, 199 followed by DRAW 1, 319, 199 drew nothing at all -- one pixel past the surface. Fixed in the same line, because it is what makes "SCALE gives a C128 listing the whole window" true rather than nearly true. The akgl test renders against a 128x128 target, deliberately smaller than the old constants: a SCALE still dividing by them misses it entirely rather than landing somewhere plausible. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
67
TODO.md
67
TODO.md
@@ -800,13 +800,43 @@ behaviour to port. They matter to somebody typing in a listing out of a C128 man
|
||||
|
||||
17. **`GRAPHIC` records its mode but honours only one consequence of it.** 7.0's five modes
|
||||
differ in bitmap resolution and in whether the bottom of the screen stays text. Neither
|
||||
means anything against a host's renderer, whose size the interpreter does not know and
|
||||
does not own. The mode is stored, an out-of-range one is refused because that is a typo
|
||||
worth catching, and the one observable rule is that mode 0 is text.
|
||||
means anything against a host's renderer, whose size the interpreter does not own. The
|
||||
mode is stored, an out-of-range one is refused because that is a typo worth catching, and
|
||||
the one observable rule is that mode 0 is text. The mode is readable as `RGR(0)`, which
|
||||
is 7.0's whole `RGR` and the one field of ours that is.
|
||||
|
||||
18. **Coordinates reaching a backend are BASIC's 320x200 space, and scaling to the window is
|
||||
the host's job.** The interpreter cannot ask the renderer how big it is without owning it.
|
||||
`SCALE` maps user coordinates onto that space; with `SCALE` off they pass through.
|
||||
18. **A coordinate reaching a backend is a device pixel, and the whole of the host's window
|
||||
is reachable from BASIC.** This used to read "coordinates are BASIC's 320x200 space and
|
||||
scaling to the window is the host's job", on the reasoning that the interpreter cannot
|
||||
ask the renderer how big it is without owning it. **That reasoning was wrong twice over**,
|
||||
which is what §8 item 9 came to say.
|
||||
|
||||
It was wrong about the mechanism: not owning a thing is no bar to *asking* it, and the
|
||||
backend record is how everything else here asks. `akbasic_GraphicsBackend` grew a `size`
|
||||
entry point, `require_graphics()` calls it before every verb that draws -- so a resized
|
||||
window is honoured between two statements rather than at attach -- and 320x200 became
|
||||
the fallback for a backend that leaves `size` NULL. It is the record's one optional
|
||||
entry point, so a host written against the old header keeps working and gets exactly the
|
||||
behaviour it used to get.
|
||||
|
||||
And it was wrong about the description: nothing ever stretched anything. With `SCALE`
|
||||
off a coordinate was passed straight to `akgl_draw_*` as a pixel address, so an 800x600
|
||||
window drew a C128 listing into its top-left 320x200 corner and left the rest unused.
|
||||
The documentation described a coordinate transform that did not exist.
|
||||
|
||||
**What changed observably** is `SCALE`, which now maps user coordinates onto the device
|
||||
rather than onto the constants, and `RGR(1)` / `RGR(2)`, which report the drawing
|
||||
surface's width and height so a program can use a window whose size it did not choose.
|
||||
A C128 listing draws in the corner as it always did; `SCALE 1, 319, 199` gives it the
|
||||
whole window.
|
||||
|
||||
**One fix rode along, in the same line of code and too small to defer.** `SCALE` mapped
|
||||
`xmax` onto the *width*, which put the user space's far corner one pixel past the
|
||||
surface: `SCALE 1, 319, 199` then `DRAW 1, 319, 199` drew nothing at all. It maps onto
|
||||
the last pixel now, which is what makes that sentence above true rather than nearly
|
||||
true. `tests/graphics_verbs.c` and `tests/akgl_backends.c`, the latter against a
|
||||
128x128 target chosen because it is *smaller* than the old constants -- a `SCALE` still
|
||||
dividing by them misses it entirely rather than landing somewhere plausible.
|
||||
|
||||
19. **`PLAY` does not block.** On a C128 `PLAY` holds the program until the last note ends.
|
||||
§1.6 forbids that outright, so `PLAY` parses the string into a fixed queue and returns;
|
||||
@@ -1158,11 +1188,19 @@ deviations from the reference's *program*: `main.go` and the SDL half of
|
||||
last one in the source until one of them runs. The scan is textual on purpose: parsing every
|
||||
line up front would raise on lines the program would never have reached.
|
||||
|
||||
33. **Sprite coordinates are BASIC's 320×200, not the VIC-II's 0–511 by 0–255.** `MOVSPR` takes
|
||||
33. **Sprite coordinates are device pixels, not the VIC-II's 0–511 by 0–255.** `MOVSPR` takes
|
||||
the same coordinate space `DRAW` does. A C128's sprite coordinates are the raster's, offset
|
||||
so that (24, 50) is the top-left of the visible screen; reproducing that would give the
|
||||
language two coordinate systems and make `MOVSPR 1, 0, 0` put a sprite off-screen. Consistent
|
||||
with deviation 18.
|
||||
with deviation 18, which is where "the same space `DRAW` uses" is defined — and it moved,
|
||||
so this one moved with it.
|
||||
|
||||
**`SCALE` deliberately does not apply to sprites.** It is a graphics-verb transform and
|
||||
the sprite verbs do not call it, which was true before deviation 18 was rewritten and is
|
||||
worth writing down now that the two spaces can differ: with `SCALE 1, 319, 199` on, a
|
||||
`DRAW` at 160,100 and a `MOVSPR` to 160,100 land in different places. Arguably they
|
||||
should agree; not changed here because it is a decision about what `SCALE` means rather
|
||||
than a slip, and it wants its own commit.
|
||||
|
||||
34. **`MOVSPR`'s speed unit is ours.** BASIC 7.0 documents speed 0–15 with 15 fastest and says
|
||||
nothing about what a unit is worth. Here one unit is
|
||||
@@ -1757,9 +1795,18 @@ What remains, in priority order:
|
||||
almost everything links against it), which is why CI runs `src/symtab.c` instead and the
|
||||
whole-tree run is a local `cmake --build build --target mutation`.
|
||||
|
||||
9. Use the actual full SDL window for graphics operation width
|
||||
9. ~~**Use the actual full SDL window for graphics operations.**~~ **Done**, and the premise
|
||||
turned out to be half wrong in a way worth keeping. The documentation did say coordinates
|
||||
are 320x200 whatever the window is — but nothing ever stretched them: with `SCALE` off a
|
||||
coordinate went straight to `akgl_draw_*` as a pixel address, so an 800x600 window drew a
|
||||
listing into its top-left corner and left the rest unused. The described transform did not
|
||||
exist.
|
||||
|
||||
The current documentation states that graphics operations always use a 320x200 space regardless of the window's size. These verbs should be able to access the entirety of the SDL window to which they are bound.
|
||||
`akbasic_GraphicsBackend` grew an optional `size` entry point, `require_graphics()` asks it
|
||||
before every verb that draws so a resized window is honoured between statements, `SCALE`
|
||||
maps onto the answer instead of onto the constants, and `RGR(1)` / `RGR(2)` let a program
|
||||
read the size. 320x200 is now the fallback for a backend that will not answer. Deviation 18
|
||||
in §5 has the whole of it, including the off-by-one it fixed on the way.
|
||||
|
||||
11. Error codes are undefined for the user
|
||||
|
||||
|
||||
Reference in New Issue
Block a user