Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

13 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

DosWorld's BGI Pack

Graphics drivers and stroked fonts for Borland's BGI (Borland Graphics Interface) — the graphics layer used by Turbo Pascal, Turbo C and Borland C++ for DOS.

Two things ship here, and they come from very different places:

  • The drivers are original work — written from scratch in assembly, heavily optimised for the 8086, containing zero Borland code.
  • The fonts are third-party typefaces converted mechanically to BGI's .CHR stroke format. Each one keeps its own licence.

Contents

CGA2.BGI      CGA   640x200,  2 colours    (BIOS mode 06h)
CGA4.BGI      CGA   320x200,  4 colours    (BIOS mode 04h, plus a grey mode on 06h)
CGA16.BGI     CGA   160x200, 16 colours    (BIOS mode 06h, composite artifact colour)
VGA16.BGI     VGA   640x480, 16 colours    (BIOS mode 12h)

FONTS/        24 stroked fonts (.CHR) + licence texts (.TXT)
SRC/DRIVERS/  driver sources (NASM)
SRC/MKBGI/    .BIN -> .BGI packager
SRC/CHRFIX/   .CHR font checker / repairer

DOCS/BGI.MD   .BGI driver format — the driver ABI, in full
DOCS/CHR.MD   .CHR stroked-font format — the font format, in full

Documentation

Both file formats are documented from the bytes up, with worked examples:

  • DOCS/BGI.MD — the .BGI driver format: header layout, the DDOVEC dispatch table, the entry stub, the Device Information Table, and a step-by-step guide to writing your own driver.
  • DOCS/CHR.MD — the .CHR stroked-font format: every header field, the signed 7-bit stroke encoding, glyphs decoded byte by byte, working readers in C and Oberon, and a validation checklist covering the format's several silent failure modes.

Drivers

Written without Borland's code

These drivers are a clean implementation of the BGI driver ABI. Nothing is disassembled, copied, or derived from Borland's own CGA.BGI / EGAVGA.BGI binaries — the published interface is implemented directly, from the device side up. That is why they can be public domain: there is no Borland code inside to encumber them.

They are ordinary BGI drivers, so they drop straight into any Turbo Pascal or Turbo C program through initgraph / registerbgidriver.

Heavily optimised for the 8086

The drivers target a real 8086 and are written to its cost model, not to what a modern CPU would forgive. About 10,800 lines of assembly across the four, with cpu 8086 enforced — no 186+ instructions, so they run on the oldest hardware BGI ever supported.

The optimisations that matter:

  • No MUL in the hot paths. An 8086 multiply costs well over a hundred cycles. Address calculation uses a precomputed row table and glyph lookup uses three shifts — each replacing a multiply that would otherwise run per pixel or per character.
  • Whole-byte fast paths. A horizontal run of 8 same-coloured pixels is a single byte write, not eight pixel writes. Fills, bars and clipped runs all take this path.
  • Byte-aligned text fast path. Unmagnified horizontal text on a byte boundary bypasses the general glyph blitter entirely.
  • No JCXZ / LOOP. Both are slow on real silicon; equivalent sequences are used instead.
  • Clipping hoisted out of inner loops. Runs are clamped to the clip box up front, so the fast path never re-tests per pixel.

On VGA the planar path uses Graphics Controller write mode 2 with a bit mask, so all four colour planes are written in one masked read-modify-write through the latches rather than four separate passes.

CGA4 also exposes a third mode, grey (320x200x4@Grey), which issues BIOS mode 06h instead of 04h at init. The framebuffer layout is identical to the two colour palettes — same 2bpp packing, same interleave — so CalcAddr, PlotOne and every drawing routine are shared unchanged; only the BIOS mode switch differs, and mode 06h simply displays the same 2-bit image without colour.

CGA16 gets its 16 colours from composite artifact colour, not a wider palette register: it drives BIOS mode 06h (640×200, 1 bit/pixel) with the colour-burst bit enabled, and each BGI pixel is a 4-hardware-bit repeating cell that an NTSC composite decoder reads as one of 16 colours. The framebuffer is otherwise CGA2/CGA4's own layout (B800h, 80 bytes/row, even/odd interleave); only init and the 4-bit-per-pixel packing differ. It needs a composite-capable display or emulator (e.g. DOSBox-X's machine=cga_composite) — on plain RGBI hardware it still runs, but the 16 colours collapse to whatever monochrome pattern the bits happen to draw.

one screen byte (2 BGI pixels, 8 hardware bits)

┌───────────────┬───────────────┐
│  high nibble  │   low nibble  │
│   (even X)    │    (odd X)    │
│ ┌─┬─┬─┬─┐     │ ┌─┬─┬─┬─┐     │   b = one hardware bit; the 4-bit
│ │b│b│b│b│     │ │b│b│b│b│     │   pattern repeats every BGI pixel
│ └─┴─┴─┴─┘     │ └─┴─┴─┴─┘     │   and is what the composite decoder
└───────────────┴───────────────┘   reads as a colour
   BGI pixel X      BGI pixel X+1

getimage buffer sizes

The image-buffer size formula is mode-dependent — worth knowing if you allocate buffers yourself:

Driver Depth Pixels/byte getimage size
CGA2 (640×200×2) 1 bpp 8 4 + ((w+7)>>3) * h
CGA4 (320×200×4) 2 bpp 4 4 + ((w+3)>>2) * h
CGA16 (160×200×16) 4 bpp 2 4 + ((w+1)>>1) * h
VGA16 (640×480×16) 4 bpp 2 4 + ((w+1)>>1) * h

Each driver stores images packed at its own native colour depth, with every row restarting on a byte boundary — the 4 leading bytes hold width−1 and height−1. On VGA16 the buffer is packed 4bpp even though the framebuffer is planar, so getimage/putimage convert between the two.


Fonts

24 stroked fonts in BGI .CHR format, converted mechanically from freely available typefaces — mostly pixel/bitmap faces, which suit BGI's stroke model and low resolutions well.

These fonts are not ours. Each came from its original author under a free licence, and converting a typeface does not change who owns it. Every font ships with the licence text and source URL it arrived with:

Licence file Covers Terms
PO.TXT PO* — 12 fonts, Pixel Operator family CC0 1.0 (public domain)
PRESS2P.TXT PRESS2P SIL Open Font License 1.1
CANTERB.TXT CANTERB 1001Fonts Free For Commercial Use (FFC)
YOSTER.TXT YOSTER Free use; may not be re-sold in a font collection
PIXEL.TXT PIXEL Free personal/commercial; may not be sold
NBSANS.TXT NBSANS3, NBSANS4, NBSANS5 See file (itch.io release)
BITTY.TXT BITTY See file (itch.io release)
VCROSD.TXT VCROSD See file (dafont release)

Read the licence for any font you ship. Most permit commercial use, but some restrict redistribution as part of a font collection. If you want no conditions at all, the PO* family is CC0.

Why the fonts carry Borland's names

Open any .CHR here and its internal 4-character name reads TRIP, LITT, SANS — one of Borland's ten. This is deliberate and unavoidable.

The BGI runtime matches that name, case-insensitively, against a hardcoded table of its own fonts:

BOLD  EURO  GOTH  LCOM  LITT  SANS  SCRI  SIMP  TRIP  TSCR

Anything else is rejected with grInvalidFont (-13) before a single byte of glyph data is read, so a custom font has to present itself as one of the ten. The name is only a table lookup — it does not select a slot and does not affect rendering — so these fonts are assigned round-robin across the ten names. The real typeface is the filename.


Building the drivers

A driver is built in two steps: NASM assembles the source to a flat 16-bit binary, then MKBGI wraps that binary in the .BGI container.

nasm -f bin -o CGA4.BIN CGA4.ASM
mkbgi CGA4 CGA/320x200x4

SRC/DRIVERS/BUILD.BAT builds all four.

MKBGI

SRC/MKBGI/ — the packager. NASM emits a flat 16-bit image and knows nothing about the BGI container, so MKBGI reads DRIVER.BIN and writes DRIVER.BGI with the byte-exact v2.0 header the loader expects: the pk 08 08 magic, an ASCII banner, and the 10-byte header block giving the header size, driver number, code size and version.

mkbgi DRIVER [DESCRIPTION]

mkbgi CGA4   CGA/320x200x4
mkbgi CGA2   CGA/640x200x2
mkbgi CGA16  CGA/160x200x16@C
mkbgi VGA16  VGA/640x480x16

DESCRIPTION must be a single word — DOS splits the command tail on whitespace and does no quote processing, so CGA/320x200x4 works but a quoted multi-word string would not survive. It is appended to the banner as <DRIVER> BGI Device Driver - <DESCRIPTION>. The banner is cosmetic — Borland's loader does not parse it — but it identifies the driver to anyone inspecting the file.

One structural trap the tool handles for you: the header block is written twice. The first copy must follow the 00 1A end-of-banner marker immediately, at a variable offset; only the second sits at the fixed offset 0x80. Place the first block at a fixed offset instead and Borland's loader rejects the file with "driver has invalid structure". The driver image itself begins at 0xA0.

The full layout is documented field by field in DOCS/BGI.MD, so you can build the container yourself if you would rather not use the tool.


CHRFIX — font checker and repairer

SRC/CHRFIX/ holds the tool used to validate and repair every font in this pack. It is worth having if you convert your own: the .CHR format has several failure modes that produce no error message at all — the font loads happily and simply draws wrong.

chrfix FILE.CHR             check only, report problems (default)
chrfix /F FILE.CHR          repair in place
chrfix /F /N=SANS FILE.CHR  repair and set the 4-char font name
chrfix /F /S=1 FILE.CHR     repair and add 1 pixel of letter spacing

What it checks:

  1. Font name — must be one of Borland's ten, or the loader returns -13.
  2. Baseline alignment — capitals must bottom out at exactly y=0, otherwise the whole text line sits off the baseline.
  3. Coordinate overflow — stroke coordinates are signed 7-bit (-64..63). A converter that emits anything larger wraps it negative, and BGI draws that as a wild backwards stroke.
  4. Glyph terminator — every glyph must end with a move-to (width, 0). Its y returns the pen to the baseline; its x is the advance to the next character. Omit it and the text line drifts a little further with every glyph; set x to zero and characters overlap — a space with zero advance disappears entirely, running words together.
  5. Metricsorg positive, descender zero or negative.
  6. Header fields — sizes, version, table offsets, signature byte.

BGI has no separate letter-spacing setting: the gap between characters is whatever the advance leaves over after the ink, so the side bearing has to be built into the advance. That is what /S=N adjusts (negative values tighten).

Exit codes: 0 valid or repaired, 1 problems found in check-only mode, 2 usage error, 3 I/O error or not a stroked font.

Each of these checks is explained in full — with the byte layout behind it — in DOCS/CHR.MD.


License

  • Drivers, MKBGI and CHRFIX — public domain. (Unlicense) No Borland code is present in any of them; use them for anything. See LICENSE.
  • Fonts — each font keeps its own licence. See FONTS/*.TXT and the table above.

About

Public domain BGI (Borland Graphic Interace) drivers (CGA, VGA), tools, and few free fonts

Topics

Resources

Stars

2 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages