added diskfont.p8

This commit is contained in:
Irmen de Jong committed 2026-10-11 05:33:47 +02:00
1 parent 25bd60368a
commit e1f2faabe7
10 files changed
+196 -81

No files matched your search

+5 -2
View File
@@ -94,8 +94,11 @@ registers survive calls. Long operations may clobber `R12-R15`.
## Syntax Pitfalls
- Hex uses `$FF`, binary uses `%1010`, and casts use `expression as type`.
- There is no automatic type widening: `byte * byte` remains a byte. Cast
explicitly when a wider result is needed.
- There is no automatic type widening in expression results: `byte * byte`
remains a byte. Cast explicitly when a wider result is needed. Assignments,
call arguments, and mixed-type expressions do widen implicitly
(`ubyte`/`byte` to `word`/`uword` to `long`); only same-width signedness
reinterpretation (`uword` to `word` and back) needs an explicit `as` cast.
- `&` is an untyped address and `&&` is a typed pointer. Complex pointer field
assignments may require `ptr^^.field`.
- `and`, `or`, `xor`, and `not` are logical operators. Use `&`, `|`, `^`, and
@@ -0,0 +1,5 @@
%import shared_amiga_diskfont
diskfont {
%option no_symbol_prefixing, ignore_unused
}
@@ -41,6 +41,7 @@ sys {
pointer @shared IFFParseBase ; loaded from disk on demand
pointer @shared AsyncIOBase ; loaded from disk on demand
pointer @shared LowLevelBase ; kickstart 2.0+, loaded from disk on demand
pointer @shared DiskfontBase ; loaded from disk on demand
pointer @shared TimerBase ; opened on demand
pointer @shared AHIBase ; ahi.device base, opened on demand by ahi.open(); for the low-level ahi.* LVO calls
@@ -0,0 +1,5 @@
%import shared_amiga_diskfont
diskfont {
%option no_symbol_prefixing, ignore_unused
}
+1
View File
@@ -41,6 +41,7 @@ sys {
pointer @shared IFFParseBase ; kickstart 2.0+, loaded from disk on demand
pointer @shared AsyncIOBase ; loaded from disk on demand
pointer @shared LowLevelBase ; kickstart 2.0+, loaded from disk on demand
pointer @shared DiskfontBase ; loaded from disk on demand
pointer @shared TimerBase ; opened on demand
^^ubyte @shared arguments ; CLI argument string (null-terminated), or NULL if Workbench launch
@@ -0,0 +1,65 @@
;; Hand-maintained diskfont.library interface, trimmed to pre-3.0 content (up to Kickstart 2.0).
;; (Outline engine, diskfont control and tagged-font matching need 3.0+ and were removed.)
;; Library base: _DiskfontBase in prog8: sys.DiskfontBase
;; Bank: 13
%import exec
%import graphics
diskfont {
%option merge, no_symbol_prefixing
sub openlib() -> bool {
; not opened at startup: diskfont.library lives on disk (not in ROM),
; so it must be opened on demand and may legitimately fail
sys.DiskfontBase = exec.OpenLibrary("diskfont.library", 0)
return sys.DiskfontBase!=0
}
sub closelib() {
if sys.DiskfontBase!=0 {
exec.CloseLibrary(sys.DiskfontBase)
sys.DiskfontBase = 0
}
}
private graphics.TextAttr[1] openfont_attr ; scratch for openfont()
sub openfont(str name, uword size, ubyte style) -> ^^graphics.TextFont {
; simplified OpenDiskFont with no flags (style e.g. graphics.FS_NORMAL).
; Name is like "helvetica.font". Returns 0 when the font cannot be found.
^^graphics.TextAttr fa = &openfont_attr[0]
fa.Name = name
fa.YSize = size
fa.Style = style
fa.Flags = 0
return OpenDiskFont(fa)
}
extsub @bank 13 -30 = OpenDiskFont(^^graphics.TextAttr textAttr @A0) -> ^^graphics.TextFont @D0
extsub @bank 13 -36 = AvailFonts(pointer buffer @A0, long bufBytes @D0, long flags @D1) -> long @D0
extsub @bank 13 -42 = NewFontContents(pointer fontsLock @A0, str fontName @A1) -> pointer @D0
extsub @bank 13 -48 = DisposeFontContents(pointer fontContentsHeader @A1)
extsub @bank 13 -54 = NewScaledDiskFont(^^graphics.TextFont sourceFont @A0, ^^graphics.TextAttr destTextAttr @A1) -> pointer @D0
; ---- constants ----
const uword MAXFONTPATH = $0100
const uword FCH_ID = $0f00
const uword TFCH_ID = $0f02
const uword DFH_ID = $0f80
const ubyte MAXFONTNAME = $0020
const ubyte AFB_MEMORY = 0
const ubyte AFF_MEMORY = $0001
const ubyte AFB_DISK = 1
const ubyte AFF_DISK = $0002
const ubyte AFB_SCALED = 2
const ubyte AFF_SCALED = $0004
const ubyte AFB_BITMAP = 3
const ubyte AFF_BITMAP = $0008
const ubyte AFB_OTAG = 4
const ubyte AFF_OTAG = $0010
const ubyte AFB_CHARSET = 5
const ubyte AFF_CHARSET = $0020
const ubyte AFB_TYPE = 6
const ubyte AFF_TYPE = $0040
}
+79 -68
View File
@@ -3,11 +3,12 @@
; Hides NewScreen/NewWindow boilerplate behind a gfx_lores-style API:
; per-call pen, client-relative word coordinates, explicit open/close.
; Kickstart 1.3 compatible: uses only OpenScreen/OpenWindow (no taglists,
; no AllocBitMap, no DisplayID). All rasterization is done by
; no AllocBitMap, no DisplayID), except fillto() which needs SetOutlinePen (3.0+).
; All rasterization is done by
; graphics.library; filled ellipses and flood fills use AreaEllipse/Flood
; with a chip-ram TmpRas scratch buffer allocated when the window opens.
; No double buffering (use two screens/windows or raw calls for that).
; Read rastport for direct graphics.library calls, window to pump IDCMP.
; Use rastport for direct graphics.library calls, window to pump IDCMP.
%import intuition
%import graphics
@@ -33,13 +34,13 @@ amiga_gfx {
private graphics.TmpRas[1] tmpras_store
private graphics.AreaInfo[1] area_store
private graphics.TextAttr[1] font_store
private ubyte[20] area_vectors ; 5 bytes per vector, AreaEllipse needs 2
private ubyte[20] area_vectors ; 5 bytes per vector, room for 4
private pointer tmpras_buf
private long tmpras_size
sub fullscreen(uword w, uword h, ubyte ndepth, uword viewmodes, str title) -> bool {
; fullscreen custom screen + backdrop borderless window.
; viewmodes: 0 = lores, graphics.HIRES for 640px, + graphics.INTERLACE for halfbrite-height.
; viewmodes: 0 = lores, graphics.HIRES for 640px, + graphics.INTERLACE for interlaced (doubled height).
if w == 0 or h == 0
return false
if rastport != 0
@@ -48,13 +49,13 @@ amiga_gfx {
if not untitled
untitled = title[0] == 0
; NOTE: struct literals must be constant, so allocate zeroed and patch fields.
^^intuition.NewScreen ns = [0, 0, 0, 0, 0, 0 as ubyte, 0 as ubyte, 0, 0, 0, 0, 0, 0]
^^intuition.NewScreen ns = [0, 0, 0, 0, 0, ; edges, size, depth
0, 1, 0, intuition.CUSTOMSCREEN, ; pens, modes, type
0, 0, 0, 0] ; font, title, gadgets, bitmap
ns.Width = w as word
ns.Height = h as word
ns.Depth = ndepth as word
ns.BlockPen = 1
ns.Depth = ndepth
ns.ViewModes = viewmodes
ns.Type = intuition.CUSTOMSCREEN
if not untitled
ns.DefaultTitle = title
; explicit Topaz 8 screen font (ROM-resident, no diskfont needed)
@@ -72,25 +73,27 @@ amiga_gfx {
; null and "" both count as titleless.
word bar = 0
if not untitled {
bar = screen.WBorTop as word
if h as word - bar <= 0 {
bar = screen.WBorTop
if h - bar <= 0 {
void intuition.CloseScreen(screen)
screen = 0
return false
}
}
const long idcmp = intuition.IDCMP_MOUSEBUTTONS | intuition.IDCMP_RAWKEY | intuition.IDCMP_VANILLAKEY
const long flags = intuition.WFLG_BACKDROP | intuition.WFLG_BORDERLESS | intuition.WFLG_ACTIVATE | intuition.WFLG_RMBTRAP | intuition.WFLG_NOCAREREFRESH
^^intuition.NewWindow nw = [0, 0, 0, 0, 0 as ubyte, 0 as ubyte, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
^^intuition.NewWindow nw = [0, 0, 0, 0, ; edges, size
0, 1, ; pens
; RAWKEY only, never add VANILLAKEY here: with both flags set Intuition
; diverts mappable keys to the vanilla channel and starves the raw one,
; so cursor keys (and on Kickstart 1.3, all keys) stop arriving as rawkey.
; Map raw codes yourself instead; ESC is $45, cursor keys are $4c-$4f.
intuition.IDCMP_MOUSEBUTTONS | intuition.IDCMP_RAWKEY,
intuition.WFLG_BACKDROP | intuition.WFLG_BORDERLESS | intuition.WFLG_ACTIVATE | intuition.WFLG_RMBTRAP | intuition.WFLG_NOCAREREFRESH,
0, 0, 0, 0, ; no gadgets, default checkmark, title, screen
0, 0, 0, 0, 0, intuition.CUSTOMSCREEN] ; bitmap, limits, type
nw.TopEdge = bar
nw.Width = w as word
nw.Height = h as word - bar
nw.BlockPen = 1
nw.IDCMPFlags = idcmp
nw.Flags = flags
nw.Title = 0 ; backdrop window itself stays titleless and undecorated
nw.Height = h - bar
nw.Screen = screen
nw.Type = intuition.CUSTOMSCREEN
window = intuition.OpenWindow(nw)
if window == 0 {
void intuition.CloseScreen(screen)
@@ -98,9 +101,10 @@ amiga_gfx {
return false
}
depth = ndepth
intuition.ActivateWindow(window)
finish_open(true, bar)
width = w
height = (h as word - bar) as uword
height = (h - bar) as uword
graphics.SetDrMd(rastport, graphics.RP_JAM1)
if untitled {
; ShowTitle(FALSE) renders the bar behind all windows; do it with
@@ -111,31 +115,31 @@ amiga_gfx {
return true
}
sub windowed(uword w, uword h, str title) -> bool {
; fixed-size window on the Workbench screen. Works everywhere,
sub windowed(uword x, uword y, uword w, uword h, str title) -> bool {
; fixed-size window on the Workbench screen at position (x,y). Works everywhere,
; but depth/palette are the Workbench's: use palette() sparingly.
if w == 0 or h == 0
return false
if rastport != 0
close()
screen = 0
const long idcmp = intuition.IDCMP_CLOSEWINDOW | intuition.IDCMP_REFRESHWINDOW | intuition.IDCMP_VANILLAKEY | intuition.IDCMP_MOUSEBUTTONS
const long flags = intuition.WFLG_CLOSEGADGET | intuition.WFLG_DRAGBAR | intuition.WFLG_DEPTHGADGET | intuition.WFLG_ACTIVATE
^^intuition.NewWindow nw = [0, 0, 0, 0, 0 as ubyte, 0 as ubyte, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
nw.LeftEdge = 10
nw.TopEdge = 20
^^intuition.NewWindow nw = [0, 0, 0, 0, ; edges, size
255, 255, ; pens
; RAWKEY only, see fullscreen() for why.
intuition.IDCMP_CLOSEWINDOW | intuition.IDCMP_REFRESHWINDOW | intuition.IDCMP_MOUSEBUTTONS | intuition.IDCMP_RAWKEY,
intuition.WFLG_CLOSEGADGET | intuition.WFLG_DRAGBAR | intuition.WFLG_DEPTHGADGET | intuition.WFLG_ACTIVATE,
0, 0, 0, 0, ; no gadgets, default checkmark, title, screen
0, 0, 0, 0, 0, intuition.WBENCHSCREEN] ; bitmap, limits, type
nw.LeftEdge = x as word
nw.TopEdge = y as word
nw.Width = w as word
nw.Height = h as word
nw.DetailPen = 255
nw.BlockPen = 255
nw.IDCMPFlags = idcmp
nw.Flags = flags
nw.Title = title
nw.Type = intuition.WBENCHSCREEN
window = intuition.OpenWindow(nw)
if window == 0
return false
depth = 0
intuition.ActivateWindow(window)
finish_open(false, 0)
graphics.SetDrMd(rastport, graphics.RP_JAM1)
return true
@@ -168,7 +172,7 @@ amiga_gfx {
if width == 0 or height == 0
return
graphics.SetAPen(rastport, pen)
graphics.RectFill(rastport, origin_x, origin_y, (origin_x + width) as word - 1, (origin_y + height) as word - 1)
graphics.RectFill(rastport, origin_x, origin_y, (origin_x + width) - 1, (origin_y + height) - 1)
}
sub plot(word x, word y, ubyte pen) {
@@ -231,7 +235,7 @@ amiga_gfx {
if radius < 0
return
graphics.SetAPen(rastport, pen)
void do_area_ellipse(cx, cy, aspect_rx(radius), radius)
do_area_ellipse(cx, cy, aspect_rx(radius), radius)
}
sub filled_oval(word cx, word cy, word rx, word ry, ubyte pen) {
@@ -239,7 +243,7 @@ amiga_gfx {
if rx <= 0 or ry <= 0
return
graphics.SetAPen(rastport, pen)
void do_area_ellipse(cx, cy, aspect_rx(rx), ry)
do_area_ellipse(cx, cy, aspect_rx(rx), ry)
}
sub text(word x, word y, str s, ubyte pen) {
@@ -265,16 +269,15 @@ amiga_gfx {
; tweak a single colormap pen (4-bit nibbles)
pointer vp = viewport()
if vp != 0
graphics.SetRGB4(vp, index as word, red, green, blue)
graphics.SetRGB4(vp, index, red, green, blue)
}
sub scroll(word dx, word dy) {
; shift the client area; the exposed strip is cleared
word xa = origin_x
word ya = origin_y
word x2 = (origin_x + width) as word - 1
word y2 = (origin_y + height) as word - 1
graphics.ScrollRaster(rastport, dx, dy, xa, ya, x2, y2)
sub scrollrect(word dx, word dy, word x, word y, word w, word h) {
; scroll a client-relative rectangle
; the rectangle should lie inside the client area.
if w <= 0 or h <= 0
return
graphics.ScrollRaster(rastport, dx, dy, origin_x+x, origin_y+y, origin_x+x+w-1, origin_y+y+h-1)
}
inline sub readpixel(word x, word y) -> long {
@@ -294,15 +297,28 @@ amiga_gfx {
return msg.MouseX - origin_x, msg.MouseY - origin_y
}
sub imsg_wait() -> ^^intuition.IntuiMessage {
; block until the next IDCMP message arrives on our window
void exec.WaitPort(window.UserPort)
return exec.GetMsg(window.UserPort) as ^^intuition.IntuiMessage
}
sub imsg_reply(^^intuition.IntuiMessage msg) -> ^^intuition.IntuiMessage {
; reply the message and fetch the next one (0 when drained)
exec.ReplyMsg(msg as ^^exec.Message)
return exec.GetMsg(window.UserPort) as ^^intuition.IntuiMessage
}
sub fill(word x, word y, ubyte pen) {
; bucket fill: recolor the connected region holding (x,y)
void do_flood(x, y, pen, 1)
do_flood(x, y, pen, 1)
}
sub fillto(word x, word y, ubyte pen, ubyte outline) {
; boundary fill: fill until the outline-colored border
void graphics.SetOutlinePen(rastport, outline as long)
void do_flood(x, y, pen, 0)
void graphics.SetOutlinePen(rastport, outline)
do_flood(x, y, pen, 0)
}
private sub aspect_rx(word rx) -> word {
@@ -324,40 +340,37 @@ amiga_gfx {
return intuition.GetScreenViewPort(s)
}
private sub do_flood(word x, word y, ubyte pen, long mode) -> bool {
private sub do_flood(word x, word y, ubyte pen, long mode) {
if rastport == 0 or tmpras_buf == 0
return false
return
graphics.SetAPen(rastport, pen)
^^graphics.TmpRas saved = rastport.TmpRas
^^graphics.TmpRas tp = &tmpras_store[0]
void graphics.InitTmpRas(tp, tmpras_buf, tmpras_size)
rastport.TmpRas = tp
bool ok = graphics.Flood(rastport, mode, origin_x+x, origin_y+y)
void graphics.Flood(rastport, mode, origin_x+x, origin_y+y)
rastport.TmpRas = saved
return ok
}
private sub finish_open(bool custom, word bar) {
rastport = window.RPort
origin_x = window.BorderLeft as word
origin_y = window.BorderTop as word
word right = window.BorderRight as word
word bottom = window.BorderBottom as word
width = (window.Width - origin_x - right) as uword
height = (window.Height - origin_y - bottom) as uword
origin_x = window.BorderLeft
origin_y = window.BorderTop
width = (window.Width - origin_x - window.BorderRight) as uword
height = (window.Height - origin_y - window.BorderBottom) as uword
; pixel shape from the screen's ViewPort.Modes (big-endian word at offset 32)
aspect = 1
pointer vp = viewport()
if vp != 0 {
uword modes = (@(vp+32) as uword) << 8 | (@(vp+33) as uword)
if (modes & (graphics.SUPERHIRES as uword)) != 0 {
uword modes = (@(vp+32) as uword) << 8 | @(vp+33)
if (modes & graphics.SUPERHIRES) != 0 {
aspect = 4
if (modes & (graphics.INTERLACE as uword)) != 0
if (modes & graphics.INTERLACE) != 0
aspect = 2
} else {
if (modes & graphics.V_HIRES) != 0 and (modes & (graphics.INTERLACE as uword)) == 0
if (modes & graphics.V_HIRES) != 0 and (modes & graphics.INTERLACE) == 0
aspect = 2
if (modes & (graphics.INTERLACE as uword)) != 0 and (modes & graphics.V_HIRES) == 0
if (modes & graphics.INTERLACE) != 0 and (modes & graphics.V_HIRES) == 0
aspect = 0
}
}
@@ -370,14 +383,14 @@ amiga_gfx {
; one-plane Flood scratch sized to the rastport's bitmap
; (Flood requires the TmpRas to cover the whole bitmap, not just the client area)
if rastport.BitMap != 0 {
tmpras_size = rastport.BitMap.BytesPerRow as long * rastport.BitMap.Rows as long
tmpras_size = rastport.BitMap.BytesPerRow * rastport.BitMap.Rows
tmpras_buf = exec.AllocMem(tmpras_size, exec.MEMF_CHIP)
}
}
private sub do_area_ellipse(word cx, word cy, word rx, word ry) -> bool {
private sub do_area_ellipse(word cx, word cy, word rx, word ry) {
if rastport == 0 or tmpras_buf == 0
return false
return
^^graphics.TmpRas saved_tr = rastport.TmpRas
^^graphics.AreaInfo saved_ai = rastport.AreaInfo
^^graphics.TmpRas tp = &tmpras_store[0]
@@ -386,11 +399,9 @@ amiga_gfx {
rastport.TmpRas = tp
graphics.InitArea(ai, area_vectors, 4)
rastport.AreaInfo = ai
long err = graphics.AreaEllipse(rastport, origin_x+cx, origin_y+cy, rx, ry)
if err == 0
err = graphics.AreaEnd(rastport)
if graphics.AreaEllipse(rastport, origin_x+cx, origin_y+cy, rx, ry) == 0
void graphics.AreaEnd(rastport)
rastport.TmpRas = saved_tr
rastport.AreaInfo = saved_ai
return err == 0
}
}
@@ -16,6 +16,7 @@ graphics {
const uword LORES = 0
const ubyte LACE = $0004
const ubyte SUPERHIRES = $20
extsub @bank 3 -30 = BltBitMap(^^BitMap srcBitMap @A0, word xSrc @D0, word ySrc @D1, ^^BitMap destBitMap @A1, word xDest @D2, word yDest @D3, word xSize @D4, word ySize @D5, ubyte minterm @D6, ubyte mask @D7, pointer tempA @A2) -> long @D0
extsub @bank 3 -36 = BltTemplate(long source @A0, word xSrc @D0, word srcMod @D1, ^^RastPort destRP @A1, word xDest @D2, word yDest @D3, word xSize @D4, word ySize @D5)
extsub @bank 3 -42 = ClearEOL(^^RastPort rp @A1)
+31 -11
View File
@@ -5,7 +5,6 @@
%import amiga_gfx
%import graphics
%import intuition
%import exec
main {
uword[8] palette = [$0112, $0f00, $00f0, $000f, $0ff0, $0f0f, $00ff, $0fff]
@@ -31,24 +30,23 @@ main {
amiga_gfx.oval(240, 200, 50, 20, 6)
amiga_gfx.filled_oval(40, 60, 30, 12, 5)
amiga_gfx.plot(160, 128, 7)
amiga_gfx.text(160, 30, "amiga_gfx demo", 7)
word tw = amiga_gfx.textwidth("click to draw stuff, ESC=quit")
amiga_gfx.text(160 - tw/2, 60, "click to draw stuff, ESC=quit", 7)
amiga_gfx.text(160, 30, "amiga_gfx demo", 5)
word tw = amiga_gfx.textwidth("click to draw, arrows scroll")
amiga_gfx.text(160 - tw/2, 60, "click to draw, arrows scroll", 6)
tw = amiga_gfx.textwidth("ESC=quit")
amiga_gfx.text(160 - tw/2, 70, "ESC=quit", 7)
amiga_gfx.setcolor(7, $f, $f, $f)
; direct library escape hatch via the exposed RastPort:
^^graphics.RastPort rp = amiga_gfx.rastport
graphics.SetAPen(rp, 3)
graphics.Move(rp, 10, 240)
graphics.Draw(rp, 310, 240)
; TODO make amiga_gfx.scroll() work
}
sub interact() {
bool done = false
while not done {
void exec.WaitPort(amiga_gfx.window.UserPort)
^^intuition.IntuiMessage msg = exec.GetMsg(amiga_gfx.window.UserPort) as ^^intuition.IntuiMessage
^^intuition.IntuiMessage msg = amiga_gfx.imsg_wait()
while msg != 0 {
when msg.Class {
intuition.IDCMP_CLOSEWINDOW -> done = true
@@ -59,10 +57,32 @@ main {
if msg.Code == intuition.MENUDOWN
amiga_gfx.fillrect(mx-10, my-6, 20, 12, 2)
}
intuition.IDCMP_VANILLAKEY -> if msg.Code == 27 { done = true } ; ESC pressed?
intuition.IDCMP_RAWKEY -> {
; keyboard arrives as rawkey only: cursor keys scroll (key repeat
; scrolls smoothly), ESC quits. Key-up events (bit 7) are ignored.
; raw keycodes are positional (same on all national keymaps):
; $00 ` $01-$0A 1..0 $0B - $0C = $0D \ $0F numpad-0
; $10-$19 Q..P $1A [ $1B ] $1D-$1F numpad-1..3
; $20-$28 A..L $29 ; $2A ' $2D-$2F numpad-4..6
; $31-$37 Z..M $38 , $39 . $3A / $3C numpad-. $3D-$3F numpad-7..9
; $40 space $41 backspace $42 tab $43 numpad-enter $44 return
; $45 ESC $46 del $4A numpad-- $4C-$4F cursor up/down/right/left
; $50-$59 F1-F10 $5A-$5E numpad ( ) / * + $5F help
; $60/$61 shift l/r $62 caps $63 ctrl $64/$65 alt l/r $66/$67 amiga l/r
; source: https://wiki.amigaos.net/wiki/Keymap_Library
if (msg.Code & $80) == 0 {
when (msg.Code & $7f) {
; note: ScrollRaster moves bits towards (0,0), so the signs are flipped
$45 -> done = true ; ESC
$4c -> amiga_gfx.scrollrect(0, 8, 80, 88, 160, 120) ; up
$4d -> amiga_gfx.scrollrect(0, -8, 80, 88, 160, 120) ; down
$4e -> amiga_gfx.scrollrect(-8, 0, 80, 88, 160, 120) ; right
$4f -> amiga_gfx.scrollrect(8, 0, 80, 88, 160, 120) ; left
}
}
}
}
exec.ReplyMsg(msg as ^^exec.Message)
msg = exec.GetMsg(amiga_gfx.window.UserPort) as ^^intuition.IntuiMessage
msg = amiga_gfx.imsg_reply(msg)
}
}
}
+3
View File
@@ -1049,6 +1049,9 @@ LIBRARY_BANK_MAP = {
# 0. CONFIG - Amiga libraries to generate
# ---------------------------------------------------------------------------
# NOTE: diskfont is intentionally NOT auto-generated: shared_amiga_diskfont.p8 is
# hand-maintained, trimmed to pre-2.0 content (the SFD contains post-2.0
# outline-engine, diskfont-control and tagged-font APIs).
AMIGA_LIBS = ["exec", "dos", "graphics", "intuition", "utility", "iffparse", "arexx", "icon", "lowlevel"]
# ---------------------------------------------------------------------------