1 #include <bz/gfx/font_internal.h>
3 #include <bz/memory/allocator.h>
4 #include <bz/resources/resource.h>
5 #include <bz/types/identifier_internal.h>
7 #include <stb_truetype.h>
9 struct BZFontCodepoint
{
10 unsigned char sprite
[32*32];
11 int advanceWidth
, leftSideBearing
;
15 typedef struct BZFontCodepoint BZFontCodepoint
;
18 stbtt_fontinfo ttfFontInfo
;
24 BZFontCodepoint codepoints
[256];
27 BZFontID
bzGfxLoadFont(BZMemoryArenaID arena
, const char *identifierFmt
, ...) {
28 bzMakeIdentifier(identifier
, identifierFmt
);
30 BZResourceID handle
= bzResourcesOpenResource("font", "assets/fonts/%s.ttf", identifier
);
31 size_t length
= bzResourcesFileLength(handle
);
32 void *data
= (uint8_t *)bzMemoryAlloc(arena
, length
);
33 bzResourcesReadBytes(handle
, data
, length
);
34 bzResourcesCloseResource(handle
);
36 BZFont
*font
= (BZFont
*)bzMemoryAlloc(arena
, sizeof(BZFont
)); // FIXME
37 stbtt_InitFont(&font
->ttfFontInfo
, data
, stbtt_GetFontOffsetForIndex(data
, 0));
38 font
->scale
= stbtt_ScaleForPixelHeight(&font
->ttfFontInfo
, 20);
40 stbtt_GetFontVMetrics(&font
->ttfFontInfo
, &font
->ascent
, &font
->descent
, &font
->lineGap
);
42 // int baselineX0, baselineY0, baselineX1, baselineY1;
43 // stbtt_GetFontBoundingBox(&font->ttfFontInfo, &baselineX0, &baselineY0, &baselineX1, &baselineY1);
44 font
->baseline
= (float)font
->ascent
* font
->scale
;
46 for (int c
= 0; c
< 256; ++c
) {
47 BZFontCodepoint
*codepoint
= &font
->codepoints
[c
];
48 stbtt_MakeCodepointBitmap(&font
->ttfFontInfo
, codepoint
->sprite
, 32, 32, 32, font
->scale
, font
->scale
, c
); // fixme, box size
49 stbtt_GetCodepointHMetrics(&font
->ttfFontInfo
, c
, &codepoint
->advanceWidth
, &codepoint
->leftSideBearing
);
50 codepoint
->advanceWidth
*= font
->scale
;
51 stbtt_GetCodepointBitmapBox(&font
->ttfFontInfo
, c
, font
->scale
, font
->scale
, &codepoint
->x0
, &codepoint
->y0
, &codepoint
->x1
, &codepoint
->y1
);
52 //stbtt_GetCodepointBox(&font->ttfFontInfo, c, &codepoint->x0, &codepoint->y0, &codepoint->x1, &codepoint->y1);
53 //codepoint->x0 = (float)codepoint->x0 * font->scale;
54 //codepoint->y0 = (float)codepoint->y0 * font->scale;
55 //codepoint->x1 = (float)codepoint->x1 * font->scale;
56 //codepoint->y1 = (float)codepoint->y1 * font->scale;
66 // Displaying a character:
67 // Compute the bounding box of the character. It will contain signed values
68 // relative to <current_point, baseline>. I.e. if it returns x0,y0,x1,y1,
69 // then the character should be displayed in the rectangle from
70 // <current_point+SF*x0, baseline+SF*y0> to <current_point+SF*x1,baseline+SF*y1).
72 // Advancing for the next character:
73 // Call GlyphHMetrics, and compute 'current_point += SF * advance'.
81 unsigned char screen[20][79];
83 int main(int arg, char **argv)
86 int i,j,ascent,baseline,ch=0;
87 float scale, xpos=2; // leave a little padding in case the character extends left
88 char *text = "Heljo World!"; // intentionally misspelled to show 'lj' brokenness
90 fread(buffer, 1, 1000000, fopen("c:/windows/fonts/arialbd.ttf", "rb"));
91 stbtt_InitFont(&font, buffer, 0);
93 scale = stbtt_ScaleForPixelHeight(&font, 15);
94 stbtt_GetFontVMetrics(&font, &ascent,0,0);
95 baseline = (int) (ascent*scale);
98 int advance,lsb,x0,y0,x1,y1;
99 float x_shift = xpos - (float) floor(xpos);
100 stbtt_GetCodepointHMetrics(&font, text[ch], &advance, &lsb);
101 stbtt_GetCodepointBitmapBoxSubpixel(&font, text[ch], scale,scale,x_shift,0, &x0,&y0,&x1,&y1);
102 stbtt_MakeCodepointBitmapSubpixel(&font, &screen[baseline + y0][(int) xpos + x0], x1-x0,y1-y0, 79, scale,scale,x_shift,0, text[ch]);
103 // note that this stomps the old data, so where character boxes overlap (e.g. 'lj') it's wrong
104 // because this API is really for baking character bitmaps into textures. if you want to render
105 // a sequence of characters, you really need to render each bitmap to a temp buffer, then
106 // "alpha blend" that into the working buffer
107 xpos += (advance * scale);
109 xpos += scale*stbtt_GetCodepointKernAdvance(&font, text[ch],text[ch+1]);
113 for (j=0; j < 20; ++j) {
114 for (i=0; i < 78; ++i)
115 putchar(" .:ioVM@"[screen[j][i]>>5]);
124 void bzGfxRenderFont(BZFontRenderPixelSetFunction pixelSetFunction
, int *xPosition
, int *yPosition
, BZFontID font
, int color
, const char *text
) {
125 for (const char *c
= text
; *c
!= '\0'; ++c
) {
126 BZFontCodepoint
*codepoint
= &font
->codepoints
[*c
];
128 for (int y
= 0, i
= 0; y
< 32; ++y
) {
129 for (int x
= 0; x
< 32; ++x
, ++i
) {
130 if (codepoint
->sprite
[i
] > 100) {
131 pixelSetFunction(*xPosition
+ x
+ codepoint
->x0
, *yPosition
+ font
->baseline
+ y
+ codepoint
->y0
, color
);
136 *xPosition
+= codepoint
->advanceWidth
;