Keep what a program draws, instead of making it a sprite
A drawing lasted exactly one frame. The verbs are immediate, they went to the back buffer, SDL double-buffers and the frontend never clears -- so the only way to keep a picture was to capture it with `SSHAPE` and install it as a sprite, which is what `examples/breakout/sprites/breakout.bas` spends two of its eight sprites doing. That was TODO.md section 9 item 9. The drawing verbs now render into a layer texture the frame composites under the text and the sprites. Draw once; it is there on every frame after. **Bracketed around the step phase, not around each verb.** One pair of `SDL_SetRenderTarget` calls a frame instead of one per `DRAW`, and it is also what makes `SSHAPE` read back what the program has just drawn rather than whatever the last frame left. **The layer is transparent where nothing was drawn.** It covers the whole window and composites underneath, so an opaque one would black out the frame the moment a program issued a single `DRAW`. And a fresh SDL target texture's contents are undefined, so it is cleared on creation -- skipping that puts uninitialised memory under the first frame's text and looks like a driver bug rather than a missing memset. **The line editor forced a wrinkle worth naming.** `akbasic_frontend_akgl_pump()` is called from two places with different answers to "is a render target current": the frame loop calls it between steps, and the sink's editor calls it from *inside* a step, borrowing a frame while it waits for a typed line. SDL refuses to present while a target is current, so the pump ends the layer, presents, and puts it back only if it was the one that ended it. `akgl_frontend` caught this -- it drives a REPL session, and it failed with "You can't present on a render target" the first time the brackets went in. This does not make a drawing *visible* on its own. The text layer still repaints every row it owns, opaque, every frame, and by default it owns the whole window; `WINDOW` shrinks it and that half was already fixed. The two together are what a picture needed, and the tests assert both -- a pixel still there a frame later with nothing redrawn, and a pixel below a shrunk text area surviving the text repaint. The second assertion wipes to a non-black colour first, because against black it could not tell a transparent layer from an opaque one. The tests found two of their own bugs on the way: `stop_runtime()` was not tearing the graphics backend down, so re-initialising it dropped a live texture on the floor; and a first draft called `begin()` before `start_runtime()`, which re-inits the backend, so the assertion read back off an orphaned render target and passed while proving nothing. Chapters 6 and 13 stop saying a drawing has to be redrawn every frame, because it does not. The batch-boundary tear stays documented -- it bites an `SSHAPE` capture, which matters much less now that capturing is not the only way to keep a picture. Both games still run clean. 111 with akgl, 110 without. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01EwxGB6TdoVvZ11KQQME9cL
This commit is contained in:
23
TODO.md
23
TODO.md
@@ -3083,8 +3083,27 @@ reduced against `build/basic`, the stdio build, unless it says otherwise.
|
||||
routine above it that ends in a fall-through rather than an `END`, and a table of angles or
|
||||
offsets is exactly where negative numbers live. `tests/read_data.c`.
|
||||
|
||||
9. **A program that wants a picture on the screen has to spend a sprite slot on it, and
|
||||
`examples/breakout/sprites/breakout.bas` spends two of its eight on the screen itself.**
|
||||
9. ~~**A program that wants a picture on the screen has to spend a sprite slot on it, and
|
||||
`examples/breakout/sprites/breakout.bas` spends two of its eight on the screen itself.**~~
|
||||
**Done for the interpreter; the listing has not been converted yet -- that is §6 item 39.**
|
||||
|
||||
The drawing verbs now render into a layer the frame composites under the text and the
|
||||
sprites (`akbasic_graphics_akgl_begin`/`_end`/`_render`, `src/graphics_akgl.c`), so a
|
||||
drawing survives the frame it was made in. With `WINDOW` already reachable to shrink the
|
||||
text area, the two halves together are what a picture needed: draw it once, uncover it,
|
||||
and it stays. `tests/akgl_backends.c` asserts both -- a pixel still present a frame later
|
||||
with nothing redrawn, and a pixel below a shrunk text area surviving the text repaint.
|
||||
|
||||
**The layer is transparent where nothing was drawn**, which is not a detail: it covers the
|
||||
whole window and composites *underneath*, so an opaque one would black out the frame the
|
||||
moment a program issued a single `DRAW`. A fresh SDL target texture's contents are
|
||||
undefined, so it is cleared on creation; skipping that put uninitialised memory under the
|
||||
first frame's text and looked like a driver bug.
|
||||
|
||||
The remaining half of item 3 -- whether the text layer *should* own the whole window by
|
||||
default -- is untouched and is still a real question rather than a defect.
|
||||
|
||||
The original report:
|
||||
|
||||
That listing draws its play field -- walls, sixty stamped bricks, the lettering -- captures
|
||||
the whole 800 by 540 region with `SSHAPE`, and installs the capture as sprite 2. It does the
|
||||
|
||||
Reference in New Issue
Block a user