Handmade Hero»Forums»Code
Shazan Shums
159 posts
Some day I will make quality software. Programming FTW.
Problems with loading fonts need help
Edited by Shazan Shums on Reason: code color problem
I have problems loading fonts using STB_truetype . Maybe because i don't know how fonts work,i modified sample code in the header file,i look stupid.Anyways can anyone help.

Here's the code,

 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);
   }
}



And why is code colors acting weird??
Jeroen van Rijn
248 posts
A big ball of Wibbly-Wobbly, Timey-Wimey _stuff_
Problems with loading fonts need help
msmshazan
And why is code colors acting weird??
Good question. I'll put it on the list of things to look at.
Simon Anciaux
1337 posts
Problems with loading fonts need help
Have your tried stepping in your code using the debugger to verify that each step (reading the font file, initializing stb_truetype ... ) gives the expected result ?
Mārtiņš Možeiko
2559 posts / 2 projects
Problems with loading fonts need help
Edited by Mārtiņš Možeiko on
You should really run your program in debugger. It would immediately show line where the error is:
1
fread(Result.Buffer, 1, 1000000, fopen("c:/windows/fonts/times.ttf", "rb"));

Result.Buffer is NULL. So program would crash on this line. You are asking to read 1000000 bytes into NULL pointer. You need to allocate buffer before writing to it.
Shazan Shums
159 posts
Some day I will make quality software. Programming FTW.
Problems with loading fonts need help
How stupid of me anyway i allocated the buffer. But still When i print the font i get a yellow rectangle.And can anyone give links on font rendering,i guess i have to learn about it.I hope there's no hard math involved in it for a 18 year old.
Mārtiņš Možeiko
2559 posts / 2 projects
Problems with loading fonts need help
Edited by Mārtiņš Možeiko on
If DrawPixel only puts pixel at X+i & Y+j coordinates into Dest bitmap, then that's the thing that draws your rectangle (not sure where yellow color comes in, probably inside DrawPixel function).
Please verify what if your code does really what you want.

Also it seems " float xpos = 2;" value needs to be defined outside of while loop, because it needs to remember horizontal advancement for next character. Currently it is set to 2 for all chars. Use a debugger to step through the loop and examine values for all variables, check that they contain values that you expect or at least they are reasonable. Then verify what functions write to memory, do they do that in correct location, are the values reasonable, etc..

And 79 in call to stbtt_MakeCodepointBitmapSubpixel seems very suspicious. Is your bitmap really only 79 bytes "wide"? Please verify all values you use! Is that copy&paste from some example code? You shouldn't do blind copy&paste. When you copy some example code then you should question every single value and variable they use. And ask yourself questions - like does 79 really works for me? What purpose does it have? What should I change it to? etc..

If you are asking about how ttf rasterization works, then stb_truetype author description is pretty neat: https://nothings.org/gamedev/rasterize/ That doesn't include ttf parsing, but that can be read from specs: http://www.truetype-typography.com/ttspec.htm (it's a lot of information and it won't be pretty).
Shazan Shums
159 posts
Some day I will make quality software. Programming FTW.
Problems with loading fonts need help
Thanks and you are right i shouldn't copy and paste code.
50 posts
Problems with loading fonts need help
Edited by itzjac on
Sorry for reviving the thread,

I have problems with the vertical positioning of the characters, the font is loaded and rendered correctly (I think) but I can't find the vertical metrics that specifies a code point, it is only the general font metrics


1
void stbtt_GetFontVMetrics(const stbtt_fontinfo *info, int *ascent, int *descent, int *lineGap);


In the comments you can read
so you should advance the vertical position by "*ascent - *descent + *lineGap"
, but those values
are all the same for any code point. Is there a function to access vertical metrics per code point at all?

Image for your reference




Appreciate your help


EDIT:
stbtt_GetCodepointBitmap() , is the one to generate the bitmaps, preferably I keep this method.
Simon Anciaux
1337 posts
Problems with loading fonts need help
There aren't character specific vertical metrics. But the following function gives you information to let you placed the bitmap correctly. I think you just need to add "iy0" to your y position.
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.)
50 posts
Problems with loading fonts need help
Thanks, vertical alignment works as a charm!

I have tested the font using a ttf LiberationMono-Regular it has no problems.
Later I tested it using arial, and for that one the kerning is broken.

By following the example in the stb library

 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;
}


It seems that the xpos should just need the [advance*scale + the kern*scale], can't find what could be missing on my side.
I am not using stbtt_MakeCodepointBitmapSubpixel, then the x_shift would not be needed?





Simon Anciaux
1337 posts
Problems with loading fonts need help
You also need to use the result of stbtt_GetCodepointBitmapBox for x. Add ix0 to the x position to have the position of the bitmap.

1
2
bitmap_x = x + ix0;
x = x + ( advance + kerning ) * scale;
50 posts
Problems with loading fonts need help
Yeah, I have figured it out to include ix0, but doesn't make a difference.
So using your suggested computing, I get the same problem


Liberation mono regular works fine

LiberationMono-Regular.ttf




arial bold kerning is wrong
arialbd.ttf


times new roman kerning is wrong too
times.ttf



Am working in Win10, if that helps.

Simon Anciaux
1337 posts
Problems with loading fonts need help
Have you tried stepping in the code with a debugger an check every value (don't assume the content of a variable, verify everything) to see what causes the bitmap to be drawn at the wrong place ?
Could you share your code (if possible the smallest amount of code that compiles) ?
Mārtiņš Možeiko
2559 posts / 2 projects
Problems with loading fonts need help
There is known issue in stb_truetype related to kerning: https://github.com/nothings/stb/issues/691
I'm not sure if it is fixed already. Last year when I used stb_truetype for something I have seen this bug really happens.
50 posts
Problems with loading fonts need help
Edited by itzjac on
Thank you for pointing that out Mozeiko,

I corrected the code in the library and probably I was getting that other problem summed up, but it didn't fix the problem.

That helped me to find what the problem in my code was, the first character in the text line, was being drawn at a position of advancement, then I generated overlapped glyphs. The first character advancement must be computed after the first character in the text line is rendered.

After testing with different fonts, I wonder, how can I find another font that has no gpos nor kern
  • LiberationMono_Regular: not gpos nor kern values
  • arialdb: gpos and kern exist
  • times: gpos and kern exist


Looked up for another system font that has "Regular" in the description, DUBAI-REGULAR.ttf, but it has gpos and kern.
Couldn't locate in the font description those details fontssquirrel.


Here the resulting kerning for my fonts with Notepad

Liberation Mono
Times
ArialBold