Add TrueType font support via stb_truetype.h
Integrate stb_truetype.h to rasterize TTF glyphs into 1-bit .FNT v3 format consumed by Win3.x display drivers. Key implementation detail: .FNT bitmaps use column-major byte order (all rows of byte-column 0 first, then byte-column 1, etc.), not row-major. New API: wdrvLoadFontTtf(path, pointSize) loads any TTF at any size. Demo 7 renders Liberation Sans/Serif/Mono at 16/20/24pt. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
e8a7812233
commit
fbb1cce5c3
11 changed files with 5449 additions and 6 deletions
4
.gitattributes
vendored
4
.gitattributes
vendored
|
|
@ -8,3 +8,7 @@
|
|||
*.BMP filter=lfs diff=lfs merge=lfs -text
|
||||
*.ICO filter=lfs diff=lfs merge=lfs -text
|
||||
*.png filter=lfs diff=lfs merge=lfs -text
|
||||
*.FON filter=lfs diff=lfs merge=lfs -text
|
||||
*.fon filter=lfs diff=lfs merge=lfs -text
|
||||
*.TTF filter=lfs diff=lfs merge=lfs -text
|
||||
*.ttf filter=lfs diff=lfs merge=lfs -text
|
||||
|
|
|
|||
|
|
@ -80,8 +80,10 @@ windriver/
|
|||
(386 protected mode with WF_PMODE + WF_CPU386). v2 (0x0200) is rejected at runtime.
|
||||
- **v3 char table**: at file offset 0x94 (fs30CharOffset), 6-byte entries {WORD width, DWORD offset}.
|
||||
The DWORD offset is absolute from the font segment base. Use FntCharEntry30T.
|
||||
- **Bitmap layout**: per-character contiguous (16 bytes per char for 8x16 font, stride=1 between rows).
|
||||
VGA BIOS 8x16 font (INT 10h AH=11h AL=30h BH=06) is already in this format — no transpose needed.
|
||||
- **Bitmap layout**: per-character contiguous, **column-major** byte order. For each character,
|
||||
all pixHeight rows of byte-column 0 come first, then all rows of byte-column 1, etc.
|
||||
Address formula: `(byteCol * pixHeight) + row`. For 8px-wide chars (1 byte column), this
|
||||
is identical to row-major. VGA BIOS 8x16 font is already in this format — no transpose needed.
|
||||
- **lpClipRect must NOT be NULL**: VBESVGA's get_clip unconditionally dereferences lpClipRect
|
||||
(STRBLT.ASM:1008 "We assume that we will never get passed a null rectangle"). Pass a RECT
|
||||
covering the full screen (0, 0, 0x7FFF, 0x7FFF).
|
||||
|
|
@ -118,8 +120,10 @@ windriver/
|
|||
Correct v3 offset = v2offset + shift (where shift = newBitmapOff - origBitsOff)
|
||||
- `wdrvLoadFontFon(path, index)` loads from .FON; `wdrvLoadFontFnt(path)` loads raw .FNT
|
||||
- `wdrvLoadFontBuiltin()` returns the VGA ROM 8x16 singleton; must NOT be passed to wdrvUnloadFont
|
||||
- `wdrvLoadFontTtf(path, pointSize)` loads TrueType via stb_truetype, rasterizes to 1-bit v3 FNT
|
||||
- `wdrvExtTextOut` takes a `WdrvFontT font` parameter (NULL = built-in)
|
||||
- Available test fonts in `fon/`: COURE.FON (8x13, 9x16, 12x20), SSERIFE.FON, SERIFE.FON, VGASYS.FON, etc.
|
||||
- Available TTF fonts in `ttf/`: LIBMONO.TTF, LIBSANS.TTF, LIBSERIF.TTF (Liberation family)
|
||||
|
||||
## Current Demo Status
|
||||
- S3TRIO.DRV, VBESVGA.DRV, VGA.DRV, ET4000.DRV all work: Load → Enable → Draw → Disable → Unload
|
||||
|
|
@ -128,6 +132,7 @@ windriver/
|
|||
- Demo 3: Lines/starburst (Output/Polyline) — works
|
||||
- Demo 4: Screen-to-screen blit (BitBlt SRCCOPY) — works
|
||||
- Demo 5: ExtTextOut text rendering — works (VBESVGA.DRV)
|
||||
- Demo 7: TrueType font rendering at multiple sizes — works
|
||||
- VGA.DRV: 640x480 4-plane 16-color mode; limited color palette but functional
|
||||
- ET4000.DRV: 640x480 8bpp on svga_et4000; software-only, no hw acceleration
|
||||
- Drivers stored in `drivers/` directory, copied to `bin/` during build
|
||||
|
|
|
|||
3
Makefile
3
Makefile
|
|
@ -18,7 +18,7 @@ DJGPP_PREFIX ?= $(HOME)/djgpp/djgpp
|
|||
|
||||
CC = $(DJGPP_PREFIX)/bin/i586-pc-msdosdjgpp-gcc
|
||||
CFLAGS = -Wall -Wextra -O2 -std=gnu99 -Iwin31drv
|
||||
LDFLAGS =
|
||||
LDFLAGS = -lm
|
||||
|
||||
# DJGPP binutils need libfl.so.2 which may not be installed system-wide
|
||||
export LD_LIBRARY_PATH := $(realpath tools/lib):$(LD_LIBRARY_PATH)
|
||||
|
|
@ -48,6 +48,7 @@ $(DEMO_EXE): $(DEMO_OBJ) lib | $(BINDIR)
|
|||
cp tools/TEST.BAT $(BINDIR)/
|
||||
-cp -n drivers/*.DRV $(BINDIR)/ 2>/dev/null; true
|
||||
-cp -n fon/*.FON $(BINDIR)/ 2>/dev/null; true
|
||||
-cp -n ttf/*.TTF $(BINDIR)/ 2>/dev/null; true
|
||||
|
||||
$(OBJDIR)/%.o: %.c | $(OBJDIR)
|
||||
$(CC) $(CFLAGS) -c -o $@ $<
|
||||
|
|
|
|||
46
demo.c
46
demo.c
|
|
@ -395,6 +395,52 @@ static void demoDrawing(WdrvHandleT drv)
|
|||
wdrvUnloadFont(sysFont);
|
||||
logMsg(" Font demo done\n");
|
||||
}
|
||||
|
||||
// Demo 7: TrueType font rendering
|
||||
if (info.hasExtTextOut) {
|
||||
logMsg("Demo 7: TrueType fonts\n");
|
||||
int32_t ret;
|
||||
int16_t textY = 180;
|
||||
|
||||
WdrvFontT ttfSmall = wdrvLoadFontTtf("LIBSANS.TTF", 16);
|
||||
WdrvFontT ttfMedium = wdrvLoadFontTtf("LIBSERIF.TTF", 20);
|
||||
WdrvFontT ttfLarge = wdrvLoadFontTtf("LIBMONO.TTF", 24);
|
||||
|
||||
if (ttfSmall) {
|
||||
const char *msg = "TrueType Sans 16pt: The quick brown fox jumps over the lazy dog";
|
||||
ret = wdrvExtTextOut(drv, 10, textY, msg, (int16_t)strlen(msg),
|
||||
MAKE_RGB(255, 255, 255), MAKE_RGB(0, 0, 128), true, ttfSmall);
|
||||
logMsg(" TTF small ret=%" PRId32 "\n", ret);
|
||||
textY += 22;
|
||||
} else {
|
||||
logMsg(" LIBSANS.TTF 16pt not loaded\n");
|
||||
}
|
||||
|
||||
if (ttfMedium) {
|
||||
const char *msg = "TrueType Serif 20pt: ABCDEFGHIJKLMNOPQRSTUVWXYZ";
|
||||
ret = wdrvExtTextOut(drv, 10, textY, msg, (int16_t)strlen(msg),
|
||||
MAKE_RGB(255, 255, 0), MAKE_RGB(128, 0, 0), true, ttfMedium);
|
||||
logMsg(" TTF medium ret=%" PRId32 "\n", ret);
|
||||
textY += 26;
|
||||
} else {
|
||||
logMsg(" LIBSERIF.TTF 20pt not loaded\n");
|
||||
}
|
||||
|
||||
if (ttfLarge) {
|
||||
const char *msg = "TrueType Mono 24pt: 0123456789";
|
||||
ret = wdrvExtTextOut(drv, 10, textY, msg, (int16_t)strlen(msg),
|
||||
MAKE_RGB(0, 255, 255), MAKE_RGB(0, 0, 0), true, ttfLarge);
|
||||
logMsg(" TTF large ret=%" PRId32 "\n", ret);
|
||||
textY += 30;
|
||||
} else {
|
||||
logMsg(" LIBMONO.TTF 24pt not loaded\n");
|
||||
}
|
||||
|
||||
wdrvUnloadFont(ttfSmall);
|
||||
wdrvUnloadFont(ttfMedium);
|
||||
wdrvUnloadFont(ttfLarge);
|
||||
logMsg(" TTF demo done\n");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
BIN
ttf/LIBMONO.TTF
(Stored with Git LFS)
Normal file
BIN
ttf/LIBMONO.TTF
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
ttf/LIBSANS.TTF
(Stored with Git LFS)
Normal file
BIN
ttf/LIBSANS.TTF
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
ttf/LIBSERIF.TTF
(Stored with Git LFS)
Normal file
BIN
ttf/LIBSERIF.TTF
(Stored with Git LFS)
Normal file
Binary file not shown.
|
|
@ -46,7 +46,7 @@ $(OBJDIR)/log.o: log.c log.h
|
|||
$(OBJDIR)/neload.o: neload.c neload.h neformat.h wintypes.h log.h
|
||||
$(OBJDIR)/thunk.o: thunk.c thunk.h wintypes.h log.h
|
||||
$(OBJDIR)/winstub.o: winstub.c winstub.h thunk.h wintypes.h log.h
|
||||
$(OBJDIR)/windrv.o: windrv.c windrv.h wintypes.h winddi.h neformat.h neload.h thunk.h winstub.h log.h
|
||||
$(OBJDIR)/windrv.o: windrv.c windrv.h wintypes.h winddi.h neformat.h neload.h thunk.h winstub.h log.h stb_truetype.h
|
||||
$(CC) $(WINDRV_CFLAGS) -c -o $@ $<
|
||||
|
||||
clean:
|
||||
|
|
|
|||
5079
win31drv/stb_truetype.h
Normal file
5079
win31drv/stb_truetype.h
Normal file
File diff suppressed because it is too large
Load diff
|
|
@ -46,6 +46,10 @@
|
|||
#include "winstub.h"
|
||||
#include "log.h"
|
||||
|
||||
#include <math.h>
|
||||
#define STB_TRUETYPE_IMPLEMENTATION
|
||||
#include "stb_truetype.h"
|
||||
|
||||
// ============================================================================
|
||||
// Driver instance structure (opaque handle)
|
||||
// ============================================================================
|
||||
|
|
@ -3166,6 +3170,296 @@ WdrvFontT wdrvLoadFontFon(const char *fonPath, int32_t fontIndex)
|
|||
}
|
||||
|
||||
|
||||
WdrvFontT wdrvLoadFontTtf(const char *ttfPath, int32_t pointSize)
|
||||
{
|
||||
// Read TTF file into memory
|
||||
FILE *f = fopen(ttfPath, "rb");
|
||||
if (!f) {
|
||||
logErr("windrv: wdrvLoadFontTtf: cannot open '%s'\n", ttfPath);
|
||||
setError(WDRV_ERR_FILE_NOT_FOUND);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
fseek(f, 0, SEEK_END);
|
||||
long fileSize = ftell(f);
|
||||
fseek(f, 0, SEEK_SET);
|
||||
|
||||
if (fileSize < 12 || fileSize > 0x1000000) {
|
||||
logErr("windrv: wdrvLoadFontTtf: bad file size %ld\n", fileSize);
|
||||
fclose(f);
|
||||
setError(WDRV_ERR_BAD_FONT);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
uint8_t *ttfBuf = (uint8_t *)malloc((uint32_t)fileSize);
|
||||
if (!ttfBuf) {
|
||||
fclose(f);
|
||||
setError(WDRV_ERR_NO_MEMORY);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (fread(ttfBuf, 1, (uint32_t)fileSize, f) != (size_t)fileSize) {
|
||||
logErr("windrv: wdrvLoadFontTtf: read error\n");
|
||||
free(ttfBuf);
|
||||
fclose(f);
|
||||
setError(WDRV_ERR_BAD_FONT);
|
||||
return NULL;
|
||||
}
|
||||
fclose(f);
|
||||
|
||||
// Initialize stb_truetype
|
||||
stbtt_fontinfo stbFont;
|
||||
if (!stbtt_InitFont(&stbFont, ttfBuf, 0)) {
|
||||
logErr("windrv: wdrvLoadFontTtf: stbtt_InitFont failed\n");
|
||||
free(ttfBuf);
|
||||
setError(WDRV_ERR_BAD_FONT);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Compute scale for target pixel height
|
||||
float scale = stbtt_ScaleForPixelHeight(&stbFont, (float)pointSize);
|
||||
|
||||
// Get font vertical metrics (unscaled)
|
||||
int stbAscent;
|
||||
int stbDescent;
|
||||
int stbLineGap;
|
||||
stbtt_GetFontVMetrics(&stbFont, &stbAscent, &stbDescent, &stbLineGap);
|
||||
|
||||
int32_t scaledAscent = (int32_t)(stbAscent * scale + 0.5f);
|
||||
int32_t scaledDescent = (int32_t)(-stbDescent * scale + 0.5f);
|
||||
int32_t pixHeight = scaledAscent + scaledDescent;
|
||||
if (pixHeight < 1) {
|
||||
pixHeight = pointSize;
|
||||
}
|
||||
|
||||
// Measure all glyphs (chars 32..255)
|
||||
uint16_t nChars = 224;
|
||||
uint8_t firstChar = 32;
|
||||
uint8_t lastChar = 255;
|
||||
|
||||
uint16_t advanceWidths[224];
|
||||
int32_t maxAdvance = 0;
|
||||
int32_t totalAdvance = 0;
|
||||
int32_t maxBitmapW = 0;
|
||||
bool allSameWidth = true;
|
||||
|
||||
for (int32_t i = 0; i < nChars; i++) {
|
||||
int ch = firstChar + i;
|
||||
int advance;
|
||||
int lsb;
|
||||
stbtt_GetCodepointHMetrics(&stbFont, ch, &advance, &lsb);
|
||||
|
||||
int32_t advW = (int32_t)(advance * scale + 0.5f);
|
||||
if (advW < 1) {
|
||||
advW = 1;
|
||||
}
|
||||
advanceWidths[i] = (uint16_t)advW;
|
||||
totalAdvance += advW;
|
||||
if (advW > maxAdvance) {
|
||||
maxAdvance = advW;
|
||||
}
|
||||
if (i > 0 && advanceWidths[i] != advanceWidths[0]) {
|
||||
allSameWidth = false;
|
||||
}
|
||||
|
||||
// Check bitmap bounding box too
|
||||
int x0;
|
||||
int y0;
|
||||
int x1;
|
||||
int y1;
|
||||
stbtt_GetCodepointBitmapBox(&stbFont, ch, scale, scale, &x0, &y0, &x1, &y1);
|
||||
int32_t bw = x1 - x0;
|
||||
if (bw > maxBitmapW) {
|
||||
maxBitmapW = bw;
|
||||
}
|
||||
}
|
||||
|
||||
// fsWidthBytes = sum of all per-character byte strides (matches .FON convention)
|
||||
uint32_t widthBytesSum = 0;
|
||||
for (int32_t i = 0; i < nChars; i++) {
|
||||
uint16_t s = (advanceWidths[i] + 7) / 8;
|
||||
if (s < 1) {
|
||||
s = 1;
|
||||
}
|
||||
widthBytesSum += s;
|
||||
}
|
||||
uint16_t fsWidthBytes = (uint16_t)widthBytesSum;
|
||||
|
||||
// Compute v3 layout with per-character bitmap sizes.
|
||||
// Each character's bitmap has its own row stride = ceil(charWidth/8).
|
||||
uint32_t charTableOff = 0x0094;
|
||||
uint32_t bitmapOff = charTableOff + (uint32_t)(nChars + 1) * 6;
|
||||
|
||||
uint32_t charOffsets[225];
|
||||
uint32_t curOff = bitmapOff;
|
||||
for (int32_t i = 0; i < nChars; i++) {
|
||||
charOffsets[i] = curOff;
|
||||
uint16_t byteStride = (advanceWidths[i] + 7) / 8;
|
||||
if (byteStride < 1) {
|
||||
byteStride = 1;
|
||||
}
|
||||
curOff += (uint32_t)byteStride * (uint32_t)pixHeight;
|
||||
}
|
||||
charOffsets[nChars] = charOffsets[0]; // sentinel reuses char 0
|
||||
|
||||
uint32_t devNameOff = curOff;
|
||||
uint32_t faceNameOff = devNameOff + 1;
|
||||
|
||||
// Extract face name from filename stem
|
||||
const char *baseName = ttfPath;
|
||||
for (const char *p = ttfPath; *p; p++) {
|
||||
if (*p == '/' || *p == '\\') {
|
||||
baseName = p + 1;
|
||||
}
|
||||
}
|
||||
char faceName[64];
|
||||
strncpy(faceName, baseName, sizeof(faceName) - 1);
|
||||
faceName[sizeof(faceName) - 1] = '\0';
|
||||
char *dot = strrchr(faceName, '.');
|
||||
if (dot) {
|
||||
*dot = '\0';
|
||||
}
|
||||
uint32_t faceNameLen = (uint32_t)strlen(faceName);
|
||||
uint32_t totalSize = faceNameOff + faceNameLen + 1;
|
||||
|
||||
// Allocate 16-bit accessible block
|
||||
uint32_t linearOut;
|
||||
uint16_t sel = alloc16BitBlock(totalSize, &linearOut);
|
||||
if (sel == 0) {
|
||||
free(ttfBuf);
|
||||
setError(WDRV_ERR_NO_MEMORY);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
uint8_t *base = (uint8_t *)linearOut;
|
||||
|
||||
// Fill .FNT v3 header
|
||||
FntHeader16T *hdr = (FntHeader16T *)base;
|
||||
hdr->fsVersion = 0x0300;
|
||||
hdr->fsSize = totalSize;
|
||||
hdr->fsType = 0; // raster
|
||||
hdr->fsPoints = (uint16_t)pointSize;
|
||||
hdr->fsVertRes = 96;
|
||||
hdr->fsHorizRes = 96;
|
||||
hdr->fsAscent = (uint16_t)scaledAscent;
|
||||
hdr->fsInternalLeading = 0;
|
||||
hdr->fsExternalLeading = 0;
|
||||
hdr->fsItalic = 0;
|
||||
hdr->fsUnderline = 0;
|
||||
hdr->fsStrikeOut = 0;
|
||||
hdr->fsWeight = 400;
|
||||
hdr->fsCharSet = 0; // ANSI
|
||||
hdr->fsPixWidth = allSameWidth ? advanceWidths[0] : 0;
|
||||
hdr->fsPixHeight = (uint16_t)pixHeight;
|
||||
hdr->fsPitchAndFamily = allSameWidth ? 0x30 : 0x01;
|
||||
hdr->fsAvgWidth = (uint16_t)(totalAdvance / nChars);
|
||||
hdr->fsMaxWidth = (uint16_t)maxAdvance;
|
||||
hdr->fsFirstChar = firstChar;
|
||||
hdr->fsLastChar = lastChar;
|
||||
hdr->fsDefaultChar = (uint8_t)('.' - firstChar);
|
||||
hdr->fsBreakChar = (uint8_t)(' ' - firstChar);
|
||||
hdr->fsWidthBytes = fsWidthBytes;
|
||||
hdr->fsDevice = devNameOff;
|
||||
hdr->fsFace = faceNameOff;
|
||||
hdr->fsBitsPointer = ((uint32_t)sel << 16) | bitmapOff;
|
||||
hdr->fsBitsOffset = bitmapOff;
|
||||
|
||||
// v3 extension at 0x76 already zeroed by calloc
|
||||
|
||||
// Fill v3 char table at 0x94
|
||||
FntCharEntry30T *charTable = (FntCharEntry30T *)(base + charTableOff);
|
||||
for (int32_t i = 0; i <= nChars; i++) {
|
||||
int32_t idx = (i < nChars) ? i : 0; // sentinel reuses char 0
|
||||
charTable[i].width = advanceWidths[idx];
|
||||
charTable[i].offset = charOffsets[i];
|
||||
}
|
||||
|
||||
// Rasterize glyphs and threshold to 1-bit
|
||||
for (int32_t i = 0; i < nChars; i++) {
|
||||
int ch = firstChar + i;
|
||||
int bw;
|
||||
int bh;
|
||||
int xoff;
|
||||
int yoff;
|
||||
unsigned char *bitmap = stbtt_GetCodepointBitmap(
|
||||
&stbFont, scale, scale, ch, &bw, &bh, &xoff, &yoff);
|
||||
|
||||
if (!bitmap || bw <= 0 || bh <= 0) {
|
||||
if (bitmap) {
|
||||
stbtt_FreeBitmap(bitmap, NULL);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
// Position glyph within the fixed-height cell.
|
||||
// xoff/yoff are relative to the pen position; use directly and
|
||||
// let the bounds checks clip anything outside the cell.
|
||||
int32_t cellY = scaledAscent + yoff;
|
||||
|
||||
uint16_t charStride = (advanceWidths[i] + 7) / 8;
|
||||
if (charStride < 1) {
|
||||
charStride = 1;
|
||||
}
|
||||
uint8_t *dst = base + charOffsets[i];
|
||||
|
||||
// .FNT bitmap format is column-major: all pixHeight rows of
|
||||
// byte-column 0 first, then all rows of byte-column 1, etc.
|
||||
// Layout: dst[(byteCol * pixHeight) + row] bit = MSB-first
|
||||
for (int row = 0; row < bh; row++) {
|
||||
int32_t dstRow = cellY + row;
|
||||
if (dstRow < 0 || dstRow >= pixHeight) {
|
||||
continue;
|
||||
}
|
||||
for (int col = 0; col < bw; col++) {
|
||||
int32_t dstCol = xoff + col;
|
||||
if (dstCol < 0 || dstCol >= (int32_t)(charStride * 8)) {
|
||||
continue;
|
||||
}
|
||||
uint8_t alpha = bitmap[row * bw + col];
|
||||
if (alpha >= 128) {
|
||||
uint32_t byteCol = (uint32_t)dstCol / 8;
|
||||
dst[byteCol * pixHeight + dstRow] |= (0x80 >> (dstCol & 7));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
stbtt_FreeBitmap(bitmap, NULL);
|
||||
}
|
||||
|
||||
// Write device name (empty) and face name
|
||||
base[devNameOff] = '\0';
|
||||
memcpy(base + faceNameOff, faceName, faceNameLen + 1);
|
||||
|
||||
// Done with TTF data
|
||||
free(ttfBuf);
|
||||
|
||||
// Allocate font handle
|
||||
struct WdrvFontS *font = (struct WdrvFontS *)calloc(1, sizeof(struct WdrvFontS));
|
||||
if (!font) {
|
||||
free16BitBlock(sel, linearOut);
|
||||
setError(WDRV_ERR_NO_MEMORY);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
font->fontSel = sel;
|
||||
font->fontLinear = linearOut;
|
||||
font->fontSize = totalSize;
|
||||
font->pixHeight = (uint16_t)pixHeight;
|
||||
font->pixWidth = allSameWidth ? advanceWidths[0] : 0;
|
||||
font->fsVersion = 0x0300;
|
||||
strncpy(font->faceName, faceName, sizeof(font->faceName) - 1);
|
||||
font->faceName[sizeof(font->faceName) - 1] = '\0';
|
||||
|
||||
dbg("windrv: wdrvLoadFontTtf: '%s' %dpt -> %dx%d (max=%d avg=%d) sel=%04X size=%" PRIu32 "\n",
|
||||
faceName, (int)pointSize,
|
||||
allSameWidth ? (int)advanceWidths[0] : 0, (int)pixHeight,
|
||||
(int)maxAdvance, (int)(totalAdvance / nChars),
|
||||
sel, totalSize);
|
||||
|
||||
return font;
|
||||
}
|
||||
|
||||
|
||||
void wdrvUnloadFont(WdrvFontT font)
|
||||
{
|
||||
if (!font || font == &gBuiltinFont) {
|
||||
|
|
|
|||
|
|
@ -174,8 +174,13 @@ WdrvFontT wdrvLoadFontFnt(const char *fntPath);
|
|||
// The returned handle must NOT be passed to wdrvUnloadFont.
|
||||
WdrvFontT wdrvLoadFontBuiltin(void);
|
||||
|
||||
// Unload a font previously loaded with wdrvLoadFontFon or wdrvLoadFontFnt.
|
||||
// Silently ignores NULL and the built-in font.
|
||||
// Load a font from a TrueType (.TTF) file at the given point size.
|
||||
// Rasterizes glyphs to 1-bit bitmaps and packs into .FNT v3 format.
|
||||
// Returns NULL on failure (call wdrvGetLastError for details).
|
||||
WdrvFontT wdrvLoadFontTtf(const char *ttfPath, int32_t pointSize);
|
||||
|
||||
// Unload a font previously loaded with wdrvLoadFontFon, wdrvLoadFontFnt,
|
||||
// or wdrvLoadFontTtf. Silently ignores NULL and the built-in font.
|
||||
void wdrvUnloadFont(WdrvFontT font);
|
||||
|
||||
// ============================================================================
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue