LLX > Neil Parker > Apple II > AMPERFONT
AMPERFONT is an add-on for Applesoft which adds a set of commands for drawing text on the hi-res screen using Apple IIGS fonts. Any IIGS bitmap font can be used, as long as you can find room for it in memory (Truetype fonts for Pointless cannot be used). It works on any Apple II with at least 64K of RAM and Applesoft in ROM. A machine with a lowercase keyboard is recommended - AMPERFONT can display lowercase characters on any Apple II (if you've selected a font that has them), but no provisions have been made for typing lowercase on uppercase-only systems.
AMPERFONT installs itself above HIMEM, between BASIC.SYSTEM and its file buffers. It consumes 1.25K of memory, lowering HIMEM (if AMPERFONT is the first such module loaded) to 37120 ($9100). If you BRUN it a second time, it will install a second copy of itself, consuming another 1.25K of memory, so a means has been provided by which your program can detect whether AMPERFONT is already installed.
AMPERFONT and its source code are freeware, and may be restributed in accordance with the terms in the included LICENSE file (a 3-clause BSD license).
This installs AMPERFONT. It loads at memory location 8192 ($2000), and
then relocates itself above HIMEM, and points the
USR vectors at itself.
AMPERFONT has been designed to coexist peacefully with other above-HIMEM modules, and unlike some such modules, it need not be the first one loaded.
This command (note the quote marks...they're part of the command name) does nothing. Its purpose is to help you detect whether or not AMPERFONT has already been loaded, so you can avoid loading it more than once and wasting 1.25K of memory. For example,
10 ON PEEK (116) > 145 OR PEEK (1015) = 190 GOTO 40: ONERR GOTO 30 20 & "AMPERFONT": POKE 216,0: GOTO 50 30 CALL 62248: POKE 216,0 40 PRINT CHR$ (4);"BRUN AMPERFONT" 50 REM The rest of your program starts here
PEEK (116) is the high byte of HIMEM - comparing it to 145
($91) tests whether HIMEM is already low enough to accommodate a
PEEK (1015) is the high byte of the
& vector - if it's 190 ($BE), then no
routine has yet been connected.)
& LOAD numeric-expression
This tells AMPERFONT where in memory to find the font you want to use
numeric-expression is any expression that evaluates to
an address in memory. The supplied address must point to the first byte of
an Apple IIGS bitmap font, but AMPERFONT doesn't try to verify this - if you
give it a bad address, it will merrily go crazy trying to draw random
You must get the font into memory before using
100 PRINT CHR$ (4);"BLOAD FONTS/CHICAGO.12,T$C8,A16384" 110 & LOAD 16384
& LOAD deposits a pointer to a (slightly modified) copy
of the font's Macintosh font header in memory locations 6 (low byte) and
7 (high byte). This can be used to
PEEK useful information
about the font, as described below. The buffer
pointed to will not move while your program is running, but its contents
will change every time you
& LOAD a new font.
& DRAW string-expression [AT numeric-expression,numeric-expression] & XDRAW string-expression [AT numeric-expression,numeric-expression]
& DRAW draws text on the current hi-res graphics screen.
Before using it, you must first select a graphics screen (with
POKE 230,value) and load a
& DRAW displays the
string-expression using the
font most recently loaded with
& LOAD. If the
AT clause is included, drawing starts at the specified
coordinates (which are normal hi-res graphics coordinates, i.e., a value in
the range 0 to 279, and a value in the range 0 to 191). If there is no
AT clause, drawing starts at the most recently plotted
The starting point is the point where the character origin point
of the string's first character will be placed. This is usually more or
less the lower left corner of the character; thus, you should expect that
most of what gets drawn will be above the Y-coordinate of the
starting point. How far above is determined by the font's ascent,
which can be
PEEKed out of the font header, as described
Note that descenders (the tails of characters like g, p, q, and y) hang
below the starting Y-coordinate. How far below is the font's
descent, which can also be
PEEKed out of the font
After the string has been drawn, the "most recently plotted point" will have same Y-coordinate as the starting point, and the X-coordinate will have moved to the right by the width of the string.
The starting point must be within the hi-res screen, but after that, any pixel that ends up past any edge of the screen will be wrapped around to reappear at the opposite edge. This is similar to how shape table shapes behave if they draw past the edge of the screen.
& DRAW draws using the current
will usually want to use
HCOLOR= 3 or
drawing on a black background, or
HCOLOR= 0 or
on a white background. Other colors are not recommended - if the font has
lots of one-pixel vertical stems, the text will probably come out illegible,
and if the vertical stems are two or more pixels wide, the text, though
probably legible, will usually be ugly.
& DRAW does not treat any character of the string as
special, not even control characers (e.g., you can't advance to a new line
CHR$ (13) into the string...you need to draw a new
string at a new position for that). This may be helpful with certain
(mostly third-party) fonts that put useful printable characters in the
control character positions.
& XDRAW works exactly like
& DRAW, except
that the current
HCOLOR is ignored, and the text is drawn by
reversing the pixels already on the screen.
& SPC( numeric-expression)
This selects how wide each character will be drawn by
numeric-expression can evaluate to one of
|0||Each character will be drawn with its natural width. This is the default setting.|
|1||Each character will be drawn as wide as the font's widest character. Characters narrower than that are widened by padding on the right with blank pixels.|
|2||Each character will be drawn as wide as the font's "0" character
These values are the same values accepted by the IIGS
& LOAD does an automatic
& SPC( 0).
This function accepts a string expression as an argument, and returns
a number giving the width in pixels of that string, calculated using the
current font and the current
& SPC() setting. It can be
used anywhere where Applesoft allows a function with a numeric result.
USR (string) returns the advance width
of the string, which is how far to the right the plotting point would be
moved if the string were to be drawn on the screen. Because characters can
have pixels that overlap past their width (this is called kerning),
this width may miss a few pixels at each end of the string.
If any other
&-handlers were installed before AMPERFONT,
they remain available, and can be invoked by putting an additional
& in front of them. Unfortunately the same convenience is
not available for
USR, because no convention has ever been
established for distinguishing between
USR handlers and
dispatching to the desired one.
The style modifications (italics, boldface, underline, outline, and shadowed) that the IIGS can apply to fonts are NOT available in AMPERFONT. But in a pinch you can get boldface like this:
& DRAW A$ AT X,Y: & DRAW A$ AT X + 1,Y
This is similar to how the IIGS does boldface.
You can simulate underlining with
HPLOT, but you'll have to
compute the coordinates of the line yourself. The
can help with this - for example,
W = USR (A$): HPLOT X,Y + 2 TO X + W, Y + 2: & DRAW A$ AT X,Y
If you need to underline something in the middle of a string, it will
help to know that after most plotting operations, including
[X]DRAW, the X-coordinate of the most recent point is
PEEK (224) + 256 * PEEK (225), and the Y-coordinate is
& LOAD command leaves a pointer to a copy of the font's
Macintosh header in memory locations 6 and 7. The buffer pointed to by this
pointer will remain at the same address as long as your program is running,
so you only need to get its address once. But its contents change after
& LOAD command to reflect the newly-loaded font.
Be careful not to use any other AMPERFONT commands between
LOAD and fetching the pointer. AMPERFONT makes heavy use of memory
locations 6 and 7 for a variety of purposes.
Several useful pieces of information can be found in the Macintosh header. Suppose the following commands have been executed:
& LOAD <address>: FH = PEEK (6) + 256 * PEEK (7)
PEEKs of the following addresses reveal the following
information (when two addresses are listed, the first holds the low
byte and the second holds the high byte):
||The pointer to the font's bitmap. Fonts normally store the Macintosh font type here, but AMPERFONT has no use for that, so it stores bitmap pointer here instead.|
||widMax: The advance width of the font's widest character. The
||kernMax: The greatest number of pixels that any character
leans to left of its character origin. Note that this is a
signed number, so you'll need a calculation like
||The pointer to the location table. Fonts normally store the negative of the descent here, but AMPERFONT has no use for that, so it puts the location table pointer here instead.|
||fRectWidth: The width of the font rectangle.|
||fRectHeight: The height of the font in pixels. Also the number of rows in the font's bitmap.|
||The pointer to the offset/width table.|
||ascent: The number of pixels that the font has above the character origin. This includes the character origin row.|
||descent: The number of pixels that the font has below the character origin. This does not include the character origin row. Note that ascent + descent = fRectHeight.|
||leading (pronounced "ledding"): The suggested amount of blank space (in pixels) to leave between adjacent lines.|
||The number of bytes in each row of the font's bitmap. Fonts normally store the number of 16-bit words per row here, but AMPERFONT converts it to the more useful number of bytes.|
(Actually, all of the fields in the header are two-byte fields. But some fields only have useful information in the low byte, and for some fields, fonts big enough to need the high byte are too big to be used by 8-bit software.)
IIGS fonts also have an additional header at the front, which AMPERFONT
ignores, but which some Applesoft programs might find useful. Suppose a
font has been loaded at "
<address>" - then the IIGS header
starts at memory location
GH = <address> + PEEK (<address>)
||The Macintosh/IIGS font family number.|
||A bit mask indicating style modifications that have been pre-applied
to the font by its designer. A sum of the following values:
||The font's official declared size. Usually matches the number at the end of the font's filename, but may or may not have any other connection to reality. (The font's true vertical size is in the fRectHeight field described above.)|
||fbrExtent: The greatest number of pixels that any character of the font can extend left or right of the character origin.|
Additionally, the font file begins with font's name, as it appears in the
Fonts menu or font chooser dialog box in Apple IIGS programs. AMPERFONT
ignores it, but Applesoft programs can find it with
PEEK - the
font's first byte is the number of characters in the name, followed
immediately by the ASCII characters of the name. For example,
200 L = PEEK (<address>):N$ = "" 210 FOR I = 1 TO L 220 N$ = N$ + CHR$ ( PEEK (<address> + I)) 230 NEXT
For more information on the font format and the meanings of its fields, see the Apple IIGS Toolbox Reference: Volume 2, pages 16-41 through 16-54, and the Apple II File Type Note for File Type $C8 (200), Auxiliary Type $0000.
In addition to AMPERFONT and its source code (Merlin Pro assembler), these contain two Applesoft programs - a brief demonstration ("DEMO") and a program to display all the characters in a font ("SHOWFONT"...choose the font to display by editing line 40) - and a folder full of fonts to play with.
None of the fonts in the FONTS folder are my work - they're all classic Macintosh and IIGS fonts from Apple Computer, some of them rarely seen since the early days of MacOS.
LLX > Neil Parker > Apple II > AMPERFONT
Original: February 22, 2021