Generate the documentation's figures from the listings they illustrate
Chapters 6 and 8 described what a verb draws in prose. Eight figures now show it, and each one is produced by running the BASIC listing printed immediately above it -- so a picture cannot drift away from the code beside it, which is the way a screenshot goes wrong and the way nothing notices. tools/screenshot.c is a second SDL host, much smaller than the frontend: dummy video driver, software renderer, run to completion, read the target back, write a PNG. It draws no text layer on purpose, so a READY in the corner is not noise in a figure about BOX and no font has to be resolved. tools/docs_screenshots.sh reads the new screenshot=NAME fence tag straight out of the markdown. size=WxH is the second tag, and SCALE's figure uses it: the point being made is a 320x200 listing filling a larger window, which cannot be made on a 320x200 surface. Two gates, answering different questions. docs_examples fails a tagged block with no image, in both configurations, so a figure cannot be added and forgotten. docs_screenshots -- a CTest, AKGL build only -- re-renders every figure and compares byte for byte, so a listing edited without regenerating fails. Only the second catches a stale picture. The PNGs are checked in because a reader on the forge has no build tree, and docs/images/README.md says loudly that they are generated. Regenerating is never part of a build: the target is run deliberately, so a make cannot put eight binary diffs in front of whoever ran it. Drawing the BOX figure caught a defect in TODO.md itself. Deviation 16 claimed in bold that BOX fills on a negative angle while its own paragraph said the fill was filed rather than implemented. BOX cannot fill, and filled_rect is reached by no verb as a result. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Co-Authored-By: Andrew Kesterson <andrew@aklabs.net>
This commit is contained in:
@@ -65,43 +65,86 @@ small number that is not a colour.
|
||||
`GRAPHIC mode` chooses a screen mode; `GRAPHIC CLR` clears it. Mode 0 is text and
|
||||
refuses to draw.
|
||||
|
||||
Every picture in this chapter is generated by running the listing above it; see
|
||||
`MAINTENANCE.md` if you are editing one.
|
||||
|
||||
### DRAW
|
||||
|
||||
```basic requires=akgl
|
||||
10 DRAW 1, 10, 20
|
||||
20 DRAW 1, 0, 0 TO 100, 100 TO 200, 0
|
||||
```basic requires=akgl screenshot=draw
|
||||
10 COLOR 1, 8
|
||||
20 DRAW 1, 20, 180 TO 90, 40 TO 160, 150 TO 230, 20 TO 300, 120
|
||||
30 COLOR 2, 6
|
||||
40 DRAW 2, 20, 190 TO 300, 190
|
||||
50 LOCATE 160, 100
|
||||
60 COLOR 3, 3
|
||||
70 DRAW 3
|
||||
```
|
||||
|
||||

|
||||
|
||||
One coordinate pair plots a point. Two or more, separated by `TO`, draw a polyline. A
|
||||
bare `DRAW 1` plots wherever `LOCATE` left the pixel cursor.
|
||||
bare `DRAW 3` — the last line above, and the single red pixel in the middle of the
|
||||
picture — plots wherever `LOCATE` left the pixel cursor.
|
||||
|
||||
### BOX
|
||||
|
||||
```basic requires=akgl
|
||||
10 BOX 1, 10, 10, 40, 40
|
||||
```basic requires=akgl screenshot=box
|
||||
10 COLOR 1, 8
|
||||
20 BOX 1, 20, 30, 130, 140
|
||||
30 COLOR 2, 6
|
||||
40 BOX 2, 180, 30, 290, 140, 30
|
||||
50 COLOR 3, 3
|
||||
60 LOCATE 300, 190
|
||||
70 BOX 3, 20, 160
|
||||
```
|
||||
|
||||
Corners, and an optional rotation angle. An unrotated `BOX` outlines rather than fills.
|
||||

|
||||
|
||||
Corners, and an optional rotation angle — the green box is the same box turned 30
|
||||
degrees about its own centre. Two coordinates instead of four take the other corner
|
||||
from the pixel cursor, which is the red box.
|
||||
|
||||
**`BOX` always outlines; it cannot fill.** BASIC 7.0 selects fill with a seventh
|
||||
argument and that is not implemented here — see Chapter 13. `PAINT` is the fill you
|
||||
have.
|
||||
|
||||
### CIRCLE
|
||||
|
||||
```basic requires=akgl
|
||||
10 CIRCLE 1, 160, 100, 50, 30
|
||||
```basic requires=akgl screenshot=circle
|
||||
10 COLOR 1, 8
|
||||
20 CIRCLE 1, 80, 70, 60, 60
|
||||
30 COLOR 2, 6
|
||||
40 CIRCLE 2, 230, 70, 75, 45
|
||||
50 COLOR 3, 3
|
||||
60 CIRCLE 3, 160, 140, 130, 50, 90, 270
|
||||
```
|
||||
|
||||
Source, centre, then the two radii — so it draws ellipses. Further arguments give a
|
||||
start angle, an end angle, a rotation and the degree increment, which is what makes it
|
||||
an arc or a polygon.
|
||||

|
||||
|
||||
Source, centre, then the two radii — equal radii give a circle and unequal ones an
|
||||
ellipse. Two further arguments are a start and an end angle, which is what makes the
|
||||
red arc: 90 to 270 is the bottom half, because angles here are degrees clockwise from
|
||||
straight up, the same convention `MOVSPR` uses. Beyond those come a rotation and the
|
||||
degree increment, and a large increment is what turns a circle into a polygon.
|
||||
|
||||
### PAINT
|
||||
|
||||
```basic requires=akgl
|
||||
10 PAINT 1, 160, 100
|
||||
```basic requires=akgl screenshot=paint
|
||||
10 COLOR 1, 8
|
||||
20 CIRCLE 1, 100, 100, 70, 70
|
||||
30 BOX 1, 180, 50, 290, 150
|
||||
40 COLOR 2, 6
|
||||
50 PAINT 2, 100, 100
|
||||
60 COLOR 3, 3
|
||||
70 PAINT 3, 230, 100
|
||||
```
|
||||
|
||||
Flood-fills the region containing a point. If the region is too large for the fill's
|
||||
own working space it stops and reports rather than leaving a half-painted screen with
|
||||
no explanation.
|
||||

|
||||
|
||||
Flood-fills the region containing a point, stopping at whatever is already drawn — so
|
||||
the outline you fill inside can come from any verb. If the region is too large for the
|
||||
fill's own working space it stops and reports rather than leaving a half-painted screen
|
||||
with no explanation.
|
||||
|
||||
### LOCATE
|
||||
|
||||
@@ -110,10 +153,23 @@ coordinates finishes.
|
||||
|
||||
### SCALE
|
||||
|
||||
```basic requires=akgl
|
||||
10 SCALE 1, 1023, 1023
|
||||
```basic requires=akgl screenshot=scale size=640x400
|
||||
10 COLOR 1, 3
|
||||
20 BOX 1, 0, 0, 319, 199
|
||||
30 SCALE 1, 319, 199
|
||||
40 COLOR 2, 6
|
||||
50 BOX 2, 0, 0, 319, 199
|
||||
60 DRAW 2, 0, 0 TO 319, 199
|
||||
```
|
||||
|
||||

|
||||
|
||||
That picture is 640 by 400, and both boxes name the same four numbers. The red one is
|
||||
drawn with `SCALE` off, so its coordinates are pixels and it covers exactly the
|
||||
top-left 320 by 200 of the window — which is what a C128 listing does here. The green
|
||||
one is drawn after `SCALE 1, 319, 199` and fills the window, and the diagonal confirms
|
||||
that 319, 199 reaches the last pixel rather than stopping one short of it.
|
||||
|
||||
Turns on user coordinates and gives their maxima. With it on, your coordinates are
|
||||
mapped onto the drawing surface: 0 is the first pixel and the maximum you gave is the
|
||||
*last* one, so `DRAW 1, 1023, 1023` above reaches the bottom-right corner rather than
|
||||
@@ -137,12 +193,21 @@ parallel passes; see Chapter 13.
|
||||
|
||||
`SSHAPE` copies a rectangle off the screen and `GSHAPE` stamps it back:
|
||||
|
||||
```basic requires=akgl
|
||||
10 BOX 1, 0, 0, 20, 20
|
||||
20 SSHAPE A$, 0, 0, 20, 20
|
||||
30 GSHAPE A$, 100, 100
|
||||
```basic requires=akgl screenshot=shapes
|
||||
10 COLOR 1, 8
|
||||
20 CIRCLE 1, 40, 40, 30, 30
|
||||
30 COLOR 2, 6
|
||||
40 PAINT 2, 40, 40
|
||||
50 SSHAPE A$, 8, 8, 72, 72
|
||||
60 GSHAPE A$, 120, 20
|
||||
70 GSHAPE A$, 200, 60
|
||||
80 GSHAPE A$, 120, 120
|
||||
```
|
||||
|
||||

|
||||
|
||||
One disc drawn, captured, and stamped three times.
|
||||
|
||||
**`A$` holds a handle, not the pixels.** On a C128 the string holds the bitmap, so a
|
||||
program could save it to disk or take its `LEN`. Here a string is a fixed 255 bytes and
|
||||
the region is a device surface, so what goes in the string is a reference to it —
|
||||
|
||||
Reference in New Issue
Block a user