-
Notifications
You must be signed in to change notification settings - Fork 3
/
VGAFont.bas
338 lines (256 loc) · 9.96 KB
/
VGAFont.bas
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
'-----------------------------------------------------------------------------------------------------------------------
' VGA Font Library
' Copyright (c) 2024 Samuel Gomes
'-----------------------------------------------------------------------------------------------------------------------
$INCLUDEONCE
'$INCLUDE:'VGAFont.bi'
'-----------------------------------------------------------------------------------------------------------------------
' TEST CODE
'-----------------------------------------------------------------------------------------------------------------------
'$RESIZE:SMOOTH
'SCREEN 12
'DIM myFont AS PSF1Type
'DIM i AS LONG: FOR i = 1 TO _WIDTH
' CIRCLE (RND * _WIDTH, RND * _HEIGHT), RND * _HEIGHT, RND * 16
'NEXT
'IF PSF1_LoadFontFromPath("..\VGA-Font-Editor\fonts\8x16\DIG8X16.psf", myFont) THEN
' PSF1_DrawString "Hello, world!", 16, 16
' _PRINTMODE _KEEPBACKGROUND
' PSF1_DrawString "Hello, world!", 32, 32
' _PRINTMODE _ONLYBACKGROUND
' PSF1_DrawString "Hello, world!", 48, 48
'END IF
'END
'-----------------------------------------------------------------------------------------------------------------------
' Draws a single character at x, y using the active font
SUB PSF1_DrawCharacter (cp AS _UNSIGNED _BYTE, x AS LONG, y AS LONG)
$CHECKING:OFF
SHARED __CurPSF AS PSF1Type
DIM AS LONG uy, r, t, p, bc, pm
r = x + __CurPSF.size.x - 1 ' calculate right just once
bc = _BACKGROUNDCOLOR
pm = _PRINTMODE
' Go through the scan line one at a time
FOR uy = 1 TO __CurPSF.size.y
' Get the scan line and pepare it
p = ASC(__CurPSF.bitmap, __CurPSF.size.y * cp + uy)
p = 256 * (p + (256 * (p > 127)))
' Draw the line
t = y + uy - 1
SELECT CASE pm
CASE 1
LINE (x, t)-(r, t), , , p
CASE 2
LINE (x, t)-(r, t), , , NOT p
CASE ELSE
LINE (x, t)-(r, t), bc
LINE (x, t)-(r, t), , , p
END SELECT
NEXT
$CHECKING:ON
END SUB
' Draws a string at x, y using the active font
SUB PSF1_DrawString (text AS STRING, x AS LONG, y AS LONG)
$CHECKING:OFF
SHARED __CurPSF AS PSF1Type
DIM AS LONG uy, l, r, t, p, cidx, bc, pm, cp, sLen
bc = _BACKGROUNDCOLOR
pm = _PRINTMODE
sLen = LEN(text)
' We will iterate through the whole text
FOR cidx = 1 TO sLen
cp = ASC(text, cidx) ' find the character to draw
l = x + (cidx - 1) * __CurPSF.size.x ' calculate the starting x position for this character
r = l + __CurPSF.size.x - 1 ' calculate right
' Next go through each scan line and draw those
FOR uy = 1 TO __CurPSF.size.y
' Get the scan line and prepare it
p = ASC(__CurPSF.bitmap, __CurPSF.size.y * cp + uy)
p = 256 * (p + (256 * (p > 127)))
' Draw the scan line
t = y + uy - 1
SELECT CASE pm
CASE 1
LINE (l, t)-(r, t), , , p
CASE 2
LINE (l, t)-(r, t), , , NOT p
CASE ELSE
LINE (l, t)-(r, t), bc
LINE (l, t)-(r, t), , , p
END SELECT
NEXT
NEXT
$CHECKING:ON
END SUB
' Returns the current font width
FUNCTION PSF1_GetFontWidth~%%
$CHECKING:OFF
SHARED __CurPSF AS PSF1Type
PSF1_GetFontWidth = __CurPSF.size.x
$CHECKING:ON
END FUNCTION
' Returns the current font height
FUNCTION PSF1_GetFontHeight~%%
$CHECKING:OFF
SHARED __CurPSF AS PSF1Type
PSF1_GetFontHeight = __CurPSF.size.y
$CHECKING:ON
END FUNCTION
' Return the onsreen length of a string in pixels
FUNCTION PSF1_GetDrawStringWidth& (text AS STRING)
$CHECKING:OFF
SHARED __CurPSF AS PSF1Type
PSF1_GetDrawStringWidth = LEN(text) * __CurPSF.size.x
$CHECKING:ON
END FUNCTION
' Set the active font
SUB PSF1_SetCurrentFont (psf AS PSF1Type)
$CHECKING:OFF
SHARED __CurPSF AS PSF1Type
__CurPSF = psf
$CHECKING:ON
END SUB
' Loads a PSF v1 font file from memory
' Note that this ignores the mode value
FUNCTION PSF1_LoadFontFromMemory%% (buffer AS STRING, psf AS PSF1Type)
SHARED __CurPSF AS PSF1Type
' Check if we at least have a header
IF LEN(buffer) < 5 THEN EXIT FUNCTION ' header is 4 bytes
' Check font magic id
IF ASC(buffer, 1) <> __PSF1_MAGIC0 OR ASC(buffer, 2) <> __PSF1_MAGIC1 THEN EXIT FUNCTION
' Skip mode and read the height
DIM i AS LONG: i = ASC(buffer, 4)
' Check font height
IF i = 0 THEN EXIT FUNCTION
psf.size.x = PSF1_FONT_WIDTH ' the width is always 8 for PSFv1
psf.size.y = i ' change the font height
psf.bitmap = MID$(buffer, 5, 256 * i) ' the bitmap data
' Set this as the default font if nothing is loaded
IF __CurPSF.size.x = 0 OR __CurPSF.size.y = 0 OR LEN(__CurPSF.bitmap) = NULL THEN __CurPSF = psf
PSF1_LoadFontFromMemory = TRUE
END FUNCTION
' Loads a PSF v1 font file from disk
FUNCTION PSF1_LoadFontFromFile%% (fileName AS STRING, psf AS PSF1Type)
PSF1_LoadFontFromFile = PSF1_LoadFontFromMemory(File_Load(fileName), psf)
END FUNCTION
' Changes the font height of the active font
' This will wipe out whatever bitmap the font already has
SUB PSF1_SetFontHeight (h AS _UNSIGNED _BYTE)
SHARED __CurPSF AS PSF1Type
__CurPSF.size.x = PSF1_FONT_WIDTH ' the width is always 8 for PSFv1
__CurPSF.size.y = h ' change the font height
__CurPSF.bitmap = STRING$(256 * __CurPSF.size.y, NULL) ' just allocate enough space for the bitmap
' Load default glyphs
DIM i AS LONG: FOR i = 0 TO 255
PSF1_SetGlyphDefaultBitmap i
NEXT
END SUB
' Returns the entire bitmap of a glyph in a string
FUNCTION PSF1_GetGlyphBitmap$ (cp AS _UNSIGNED _BYTE)
SHARED __CurPSF AS PSF1Type
PSF1_GetGlyphBitmap = MID$(__CurPSF.bitmap, 1 + __CurPSF.size.y * cp, __CurPSF.size.y)
END FUNCTION
' Returns the entire font as a string
FUNCTION PSF1_GetFont$
SHARED __CurPSF AS PSF1Type
PSF1_GetFont = __CurPSF.bitmap
END FUNCTION
' Sets the entire bitmap of a glyph with bmp
SUB PSF1_SetGlyphBitmap (cp AS _UNSIGNED _BYTE, bmp AS STRING)
SHARED __CurPSF AS PSF1Type
MID$(__CurPSF.bitmap, 1 + __CurPSF.size.y * cp, __CurPSF.size.y) = bmp
END SUB
' Sets the entire font from a string
FUNCTION PSF1_SetFont%% (buffer AS STRING)
SHARED __CurPSF AS PSF1Type
DIM i AS LONG: i = LEN(buffer)
' Check some absurd cases
IF i = 0 OR i MOD 256 <> 0 THEN EXIT FUNCTION
' Copy contents from the buffer
__CurPSF.bitmap = buffer
' Adjust the font height
__CurPSF.size.y = i \ 256
__CurPSF.size.x = PSF1_FONT_WIDTH ' just in case this was not set
PSF1_SetFont = TRUE
END FUNCTION
' Set the glyph's bitmap to QB64's current font glyph
SUB PSF1_SetGlyphDefaultBitmap (cp AS _UNSIGNED _BYTE)
SHARED __CurPSF AS PSF1Type
DIM img AS LONG: img = _NEWIMAGE(_FONTWIDTH, _FONTHEIGHT, 256)
IF img >= -1 THEN EXIT SUB ' leave if we failed to allocate the image
DIM dst AS LONG: dst = _DEST ' save dest
_DEST img ' set img as dest
DIM f AS LONG: f = _FONT ' save the current font
' Select the best builtin font to use
SELECT CASE __CurPSF.size.y
CASE IS > 15
_FONT 16
CASE IS > 13
_FONT 14
CASE ELSE
_FONT 8
END SELECT
_PRINTSTRING (0, 0), CHR$(cp) ' render the glyph to our image
' Find the starting x, y on the font bitmap where we should start to render
DIM sx AS LONG: sx = __CurPSF.size.x \ 2 - _FONTWIDTH \ 2
DIM sy AS LONG: sy = __CurPSF.size.y \ 2 - _FONTHEIGHT \ 2
DIM src AS LONG: src = _SOURCE ' save the old source
_SOURCE img ' change source to img
' Copy the QB64 glyph
DIM AS LONG x, y, w, h
w = _FONTWIDTH
h = _FONTHEIGHT
WHILE y < h
x = 0
WHILE x < w
PSF1_SetGlyphPixel cp, sx + x, sy + y, POINT(x, y) <> 0 ' black
x = x + 1
WEND
y = y + 1
WEND
_SOURCE src ' restore source
_FONT f ' restore font
_DEST dst
_FREEIMAGE img ' free img
END SUB
' Return true if the pixel-bit at the glyphs x, y is set
FUNCTION PSF1_GetGlyphPixel%% (cp AS _UNSIGNED _BYTE, x AS LONG, y AS LONG)
SHARED __CurPSF AS PSF1Type
IF x < 0 OR x >= __CurPSF.size.x OR y < 0 OR y >= __CurPSF.size.y THEN EXIT FUNCTION
PSF1_GetGlyphPixel = _READBIT(ASC(__CurPSF.bitmap, __CurPSF.size.y * cp + y + 1), __CurPSF.size.x - x - 1)
END FUNCTION
' Sets or unsets pixel at the glyphs x, y
SUB PSF1_SetGlyphPixel (cp AS _UNSIGNED _BYTE, x AS LONG, y AS LONG, b AS _BYTE)
SHARED __CurPSF AS PSF1Type
IF x < 0 OR x >= __CurPSF.size.x OR y < 0 OR y >= __CurPSF.size.y THEN EXIT SUB
IF b THEN
ASC(__CurPSF.bitmap, __CurPSF.size.y * cp + y + 1) = _SETBIT(ASC(__CurPSF.bitmap, __CurPSF.size.y * cp + y + 1), __CurPSF.size.x - x - 1)
ELSE
ASC(__CurPSF.bitmap, __CurPSF.size.y * cp + y + 1) = _RESETBIT(ASC(__CurPSF.bitmap, __CurPSF.size.y * cp + y + 1), __CurPSF.size.x - x - 1)
END IF
END SUB
' Saves the current font to disk in PSF v1 format
' This does not check if the file exists or whatever and will happily overwrite it
' It is the caller's resposibility to check this stuff
' Note that this will set the mode value to 0
FUNCTION PSF1_SaveFont%% (fileName AS STRING)
SHARED __CurPSF AS PSF1Type
IF __CurPSF.size.x > 0 AND __CurPSF.size.y > 0 AND LEN(__CurPSF.bitmap) = 256 * __CurPSF.size.y THEN ' check if the font is valid
' Open the file for writing
DIM hFile AS LONG: hFile = FREEFILE
OPEN fileName FOR BINARY ACCESS WRITE AS hFile
' Write font id
DIM buffer AS STRING: buffer = CHR$(__PSF1_MAGIC0) + CHR$(__PSF1_MAGIC1)
PUT hFile, , buffer
' Write mode as zero
buffer = CHR$(NULL)
PUT hFile, , buffer
' Write font height
buffer = CHR$(__CurPSF.size.y)
PUT hFile, , buffer
PUT hFile, , __CurPSF.bitmap ' write the font data
CLOSE hFile
PSF1_SaveFont = TRUE
END IF
END FUNCTION
'$INCLUDE:'File.bas'