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 redistributed in accordance with the terms in the included LICENSE file (a 3-clause BSD license).
BRUN AMPERFONT
BRUN AMPERFONT
This installs AMPERFONT. It loads at memory location 8192 ($2000), and
then relocates itself above HIMEM, and points the &
and
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.
& "AMPERFONT"
& "AMPERFONT"
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
previously-installed AMPERFONT. PEEK (1015) is the high byte of the
&
vector - if it's 190 ($BE), then no &
routine has yet been connected.)
& LOAD
& LOAD numeric-expression
This tells AMPERFONT where in memory to find the font you want to use
next. The 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
junk.
You must get the font into memory before using & LOAD
,
for example,
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
and & XDRAW
& 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
HGR
, HGR2
, or POKE 230,value
) and load a
font with & LOAD
.
& 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
point.
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 PEEK
ed out of the font header, as described
below.
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 PEEK
ed out of the font
header.
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 HCOLOR
. You
will usually want to use HCOLOR= 3
or 7
for
drawing on a black background, or HCOLOR= 0
or 4
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
by putting 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()
& SPC( numeric-expression)
This selects how wide each character will be drawn by &
[X]DRAW
. The numeric-expression
can evaluate to one of
the following:
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
(CHR$ (48)
). Characters wider than that will be overlapped
by the following character. This is useful for aligning columns of
numbers.
These values are the same values accepted by the IIGS
SetFontFlags
routine. & LOAD
does an automatic
& SPC( 0)
.
USR
USR (string-expression)
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.
Technically, 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.
& USR
& USR
This command points the USR
vector at AMPERFONT's
USR
function handler. This is normally done by BRUN
AMPERFONT
, but since the USR
vector cannot easily be
used by more than one handler at a time, this provides a way to reconnect
AMPERFONT's USR
function after something else has usurped
it.
& &
If any other &
-handlers were installed before AMPERFONT,
they remain available, and can be invoked as if AMPERFONT were not present,
unless they happen to have the same name as an AMPERFONT command. In that
case, the prior handler can be invoked by putting a second &
in front of the statement.
Unfortunately the same convenience is not available for USR
(it's not clear how to identify whether a USR
call should be
passed on to another handler). At least with the & USR
command, it's possible to reconnect AMPERFONT's handler if something else
replaces it.
Styles
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 USR
function
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
PEEK (226)
.
Font Header Information
The & 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
every & 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)
Then PEEK
s 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):
FH, FH+1
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 the bitmap
pointer here instead.
FH+2
firstChar: The CHR$
code for the font's first
defined character.
FH+4
lastChar: The CHR$
code for the font's last
defined character.
FH+6
widMax: The advance width of the font's widest character. The
& SPC( 1)
command pretends all characters are
this wide.
FH+8, FH+9
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 KM = PEEK
(FH + 8) + 256 * PEEK (FH + 9): IF KM > 32767 THEN KM = KM -
65536
. Negative values mean at least one character has that many
pixels to the left of its origin; positive values mean all characters
have at least that many blank pixel columns to the right of the
origin.
FH+10, FH+11
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.
FH+12
fRectWidth: The width of the font rectangle.
FH+14
fRectHeight: The height of the font in pixels. Also the
number of rows in the font's bitmap.
FH+16, FH+17
The pointer to the offset/width table.
FH+18
ascent: The number of pixels that the font has above the
character origin. This includes the character origin row.
FH+20
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.
FH+22
leading (pronounced "ledding"): The suggested amount of blank
space (in pixels) to leave between adjacent lines.
FH+24, FH+25
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>)
+ 1
.
GH+2, GH+3
The Macintosh/IIGS font family number.
GH+4
A bit mask indicating style modifications that have been pre-applied
to the font by its designer. A sum of the following values:
1
Bold
2
Italic
4
Underline
8
Outline
16
Shadow
GH+6
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.)
GH+10, GH+11
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.
DOS 3.3 Version
The documentation above describes the ProDOS version of AMPERFONT. The
DOS 3.3 version is almost, but not quite, the same.
The DOS 3.3 version can run with 48K of RAM. It might also work with as
little as 32K, but that would be a tight squeeze. Because DOS 3.3 doesn't
require HIMEM to be page-aligned, the DOS 3.3 version consumes 1120 bytes,
instead of the 1280 bytes of the ProDOS version.
The DOS 3.3 version installs itself between HIMEM and the DOS file
buffers. This memory is safe from being trampled on by Applesoft
veriables, but not from DOS commands like FP, INT, or
MAXFILES. Therefore, rather than test for its presence as shown
under & "AMPERFONT" above, it's
probably best for a program under DOS 3.3 to just throw away any
already-loaded copy and reload from scratch. For example,
10 POKE 1013,76: POKE 1014,88: POKE 1015,255: REM Reset & vector
20 PRINT CHR$ (4);"MAXFILES 3": REM Throw away above-HIMEM buffer
30 PRINT CHR$ (4);"BRUN AMPERFONT"
40 REM The rest of your program continues here
Of course MAXFILES can be set to values other than 3 in line
20. If your program doesn't open any text files, MAXFILES 1
would leave some additional memory free.
Because BRUN AMPERFONT
moves HIMEM, a DOS 3.3 program should
avoid using any string variables until after AMPERFONT is installed.
Getting IIGS fonts onto a DOS 3.3 disk can be a bit tricky. I've found
that Copy II Plus 8.4 works better for this than Apple's utilities. For the
fonts on the AMPERFONT disk, I made copies of the ProDOS font files, and
used a filetype-changing utility to convert them to BIN files before
transferring them to the DOS 3.3 disk.
Downloads
amperfont.shk (Shrinkit archive, 79324 bytes):
ProDOS version
amprfnt.d33.sdk (Shrinkit DOS 3.3 disk, 77886
bytes): DOS 3.3 version
amperfont.zip (Zip archive, 121105 bytes):
contains two 5.25-inch disk images, one ProDOS and one DOS 3.3
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") - and a set
of fonts to play with.
None of the fonts 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.
Due to limited disk space, the documentation file is omitted from the
DOS 3.3 disk.
LLX >
Neil Parker >
Apple II > AMPERFONT
Original: February 22, 2021
Modified: September 26, 2021--Small improvements made to the parser (to play
better with other &
-handlers), and SHOWFONT fixed to ask for
the font file instead of making the user edit the program.
Modified: October 5, 2021--Added DOS 3.3 version.
Modified: January 16, 2022--Added & USR
command; DOS 3.3
relocator no longer wastes memory by rounding code size up to a full
page.
Modified: September 12, 2022--Fixed bug that made CHR$ (0)
always print as the missing character glyph even if it's not
missing.