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 | struct loaded_bitmap { void *Memory; s32 Width; s32 Height; s32 Pitch; }; struct loaded_font { stbtt_fontinfo FontInfo; r32 LineAdvance; void* Buffer; u32 MinCodePoint; u32 MaxCodePoint; u32 MaxGlyphCount; u32 GlyphCount; r32 Scale; s32 Ascent; s32 Baseline; u32 *GlyphIndexFromCodePont; u32 OnePastHigestCodePoint; }; loaded_font InitFont(const char* Filename) { loaded_font Result = {}; fread(Result.Buffer, 1, 1000000, fopen("c:/windows/fonts/times.ttf", "rb")); stbtt_InitFont(&Result.FontInfo,(u8 *)Result.Buffer,0); Result.Scale = stbtt_ScaleForPixelHeight(&Result.FontInfo, 128); stbtt_GetFontVMetrics(&Result.FontInfo, &Result.Ascent,0,0); Result.Baseline = (int) (Result.Ascent*Result.Scale); return Result; } void PrintFont(float X, float Y,char *Text,loaded_font *Source,loaded_bitmap *Dest) { int Width = Dest->Width; int Height = Dest->Height; u8 *screen = (u8 *)Dest->Memory; int ch=0 ; while (Text[ch]) { int advance,lsb,x0,y0,x1,y1; float xpos = 2; float x_shift = xpos - (float) floor(xpos); stbtt_GetCodepointHMetrics(&Source->FontInfo, Text[ch], &advance, &lsb); stbtt_GetCodepointBitmapBoxSubpixel(&Source->FontInfo, Text[ch], Source->Scale,Source->Scale,x_shift,0, &x0,&y0,&x1,&y1); stbtt_MakeCodepointBitmapSubpixel(&Source->FontInfo, screen + (((Source->Baseline) + y0)*BITMAP_BYTES_PER_PIXEL +(int) xpos + x0), x1-x0,y1-y0, 79, Source->Scale,Source->Scale,x_shift,0, Text[ch]); // note that this stomps the old data, so where character boxes overlap (e.g. 'lj') it's wrong // because this API is really for baking character bitmaps into textures. if you want to render // a sequence of characters, you really need to render each bitmap to a temp buffer, then // "alpha blend" that into the working buffer xpos += (advance * Source->Scale); if (Text[ch+1]) xpos += Source->Scale*stbtt_GetCodepointKernAdvance(&Source->FontInfo, Text[ch],Text[ch+1]); ++ch; } for (float j=0; j < Height - Y; ++j) { for (float i=0; i < Width - X; ++i) DrawPixel(Dest,X + i,Y + j,0.1,1,1); } } |
msmshazanGood question. I'll put it on the list of things to look at.
And why is code colors acting weird??
1 | fread(Result.Buffer, 1, 1000000, fopen("c:/windows/fonts/times.ttf", "rb")); |
1 | void stbtt_GetFontVMetrics(const stbtt_fontinfo *info, int *ascent, int *descent, int *lineGap); |
so you should advance the vertical position by "*ascent - *descent + *lineGap", but those values
1 2 3 4 5 6 | STBTT_DEF void stbtt_GetCodepointBitmapBox(const stbtt_fontinfo *font, int codepoint, float scale_x, float scale_y, int *ix0, int *iy0, int *ix1, int *iy1); // get the bbox of the bitmap centered around the glyph origin; so the // bitmap width is ix1-ix0, height is iy1-iy0, and location to place // the bitmap top left is (leftSideBearing*scale,iy0). // (Note that the bitmap uses y-increases-down, but the shape uses // y-increases-up, so CodepointBitmapBox and CodepointBox are inverted.) |
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 | int main(int arg, char **argv) { stbtt_fontinfo font; int i,j,ascent,baseline,ch=0; float scale, xpos=2; // leave a little padding in case the character extends left char *text = "Heljo World!"; // intentionally misspelled to show 'lj' brokenness fread(buffer, 1, 1000000, fopen("c:/windows/fonts/arialbd.ttf", "rb")); stbtt_InitFont(&font, buffer, 0); scale = stbtt_ScaleForPixelHeight(&font, 15); stbtt_GetFontVMetrics(&font, &ascent,0,0); baseline = (int) (ascent*scale); while (text[ch]) { int advance,lsb,x0,y0,x1,y1; float x_shift = xpos - (float) floor(xpos); stbtt_GetCodepointHMetrics(&font, text[ch], &advance, &lsb); stbtt_GetCodepointBitmapBoxSubpixel(&font, text[ch], scale,scale,x_shift,0, &x0,&y0,&x1,&y1); stbtt_MakeCodepointBitmapSubpixel(&font, &screen[baseline + y0][(int) xpos + x0], x1-x0,y1-y0, 79, scale,scale,x_shift,0, text[ch]); // note that this stomps the old data, so where character boxes overlap (e.g. 'lj') it's wrong // because this API is really for baking character bitmaps into textures. if you want to render // a sequence of characters, you really need to render each bitmap to a temp buffer, then // "alpha blend" that into the working buffer xpos += (advance * scale); if (text[ch+1]) xpos += scale*stbtt_GetCodepointKernAdvance(&font, text[ch],text[ch+1]); ++ch; } for (j=0; j < 20; ++j) { for (i=0; i < 78; ++i) putchar(" .:ioVM@"[screen[j][i]>>5]); putchar('\n'); } return 0; } |
1 2 | bitmap_x = x + ix0; x = x + ( advance + kerning ) * scale; |