]> git.bts.cx Git - benzene.git/blob - src/bz/gfx/font.c
Initial version
[benzene.git] / src / bz / gfx / font.c
1 #include <bz/gfx/font_internal.h>
2
3 #include <bz/memory/allocator.h>
4 #include <bz/resources/resource.h>
5 #include <bz/types/identifier_internal.h>
6 #include <stb_image.h>
7 #include <stb_truetype.h>
8
9 struct BZFontCodepoint {
10 unsigned char sprite[32*32];
11 int advanceWidth, leftSideBearing;
12 int x0, y0;
13 int x1, y1;
14 };
15 typedef struct BZFontCodepoint BZFontCodepoint;
16
17 struct BZFont {
18 stbtt_fontinfo ttfFontInfo;
19 float scale;
20 int ascent;
21 int descent;
22 int lineGap;
23 int baseline;
24 BZFontCodepoint codepoints[256];
25 };
26
27 BZFontID bzGfxLoadFont(BZMemoryArenaID arena, const char *identifierFmt, ...) {
28 bzMakeIdentifier(identifier, identifierFmt);
29
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);
35
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);
39
40 stbtt_GetFontVMetrics(&font->ttfFontInfo, &font->ascent, &font->descent, &font->lineGap);
41
42 // int baselineX0, baselineY0, baselineX1, baselineY1;
43 // stbtt_GetFontBoundingBox(&font->ttfFontInfo, &baselineX0, &baselineY0, &baselineX1, &baselineY1);
44 font->baseline = (float)font->ascent * font->scale;
45
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;
57 }
58
59 return font;
60 }
61
62 /*
63
64
65
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).
71 //
72 // Advancing for the next character:
73 // Call GlyphHMetrics, and compute 'current_point += SF * advance'.
74
75
76
77
78
79
80 char buffer[24<<20];
81 unsigned char screen[20][79];
82
83 int main(int arg, char **argv)
84 {
85 stbtt_fontinfo font;
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
89
90 fread(buffer, 1, 1000000, fopen("c:/windows/fonts/arialbd.ttf", "rb"));
91 stbtt_InitFont(&font, buffer, 0);
92
93 scale = stbtt_ScaleForPixelHeight(&font, 15);
94 stbtt_GetFontVMetrics(&font, &ascent,0,0);
95 baseline = (int) (ascent*scale);
96
97 while (text[ch]) {
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);
108 if (text[ch+1])
109 xpos += scale*stbtt_GetCodepointKernAdvance(&font, text[ch],text[ch+1]);
110 ++ch;
111 }
112
113 for (j=0; j < 20; ++j) {
114 for (i=0; i < 78; ++i)
115 putchar(" .:ioVM@"[screen[j][i]>>5]);
116 putchar('\n');
117 }
118
119 return 0;
120 }
121 */
122
123
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];
127
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);
132 }
133 }
134 }
135
136 *xPosition += codepoint->advanceWidth;
137 }
138 }