# 2D [DX9] Displaying font loaded by FreeType

## Recommended Posts

On 1/17/2019 at 3:46 PM, ddlox said:

~snip~

Hi.

I didn't see your reply, but I had some extra time to work on it today. Pretty happy I fixed some of the issues I was having but still have some slight problems.

As you can see it seems to be rendering fine until the letter 'r'... Not sure why this is happening. Especially how the letter 'g' seems to be clipping out on the top.

float CDisplayFont::DisplayText( const char * szText, int textCount, const SVector2f& pos, const SColorRect & colors, const SRectf * pClipRect )
{
SVector2f tmp ( pos.x, pos.y );

IRender * render = g_pCore->GetGraphics()->GetRender();
ISurface * surface = g_pCore->GetGraphics()->GetSurface();

float sh = 0.f;

for ( int i = 0; i < textCount; ++i )
{
const Codepoint_t cp = static_cast< Codepoint_t >( szText[ i ] );
if ( GlyphInfo_t * glyph = GetGlyphInfo( cp ) )
{
float sx = tmp.x + glyph->offsetX * m_fScaleHoriz;
/**
- m_fMaxYOffset is actually the y bearing of character 'T'
- (0,0) is the top left of the screen so this is the "correct" way to get the y coordinate
**/
float sy = tmp.y + ( m_fMaxYOffset - glyph->offsetY ) * m_fScaleVert;

float w	 = glyph->width * m_fScaleHoriz;
float h  = glyph->height * m_fScaleVert;

float tx1 = glyph->texcoords[ 0 ]; // left
float tx2 = glyph->texcoords[ 2 ]; // right
float ty1 = glyph->texcoords[ 1 ]; // top
float ty2 = glyph->texcoords[ 3 ]; // bottom

if ( szText[ i ] != ' ' )
{
// only using to get the height for drawing the line below..
if ( sh == 0.f )
sh = h;

SVertex vtx[ ] =
{
{ ( sx ),     ( sy + h ), 0.0f, 1.f, colors.BottomLeft, tx1, ty2 },
{ ( sx + w ), ( sy ),     0.0f, 1.f, colors.TopRight,   tx2, ty1 },
{ ( sx ),	  ( sy ),	  0.0f, 1.f, colors.TopLeft,    tx1, ty1 },

{ ( sx ),	  ( sy + h ), 0.0f, 1.f, colors.BottomLeft,	tx1, ty2 },
{ ( sx + w ), ( sy + h ), 0.0f, 1.f, colors.BottomRight,tx2, ty2 },
{ ( sx + w ), ( sy ),     0.0f, 1.f, colors.TopRight,	tx2, ty1 }
};

//   arguments ->    ( rl, vertex data, vertex count, topology, texture (IDirect3DTexture9) )
render->PushVertices( NULL, vtx, 6, D3DPT_TRIANGLELIST, glyph->texture->GetInternalPtr() );
}

tmp.x += static_cast< float >( glyph->advanceX >> 6 ) * m_fScaleHoriz;
}
}

// just testing, sh seems to be correct lol
surface->DrawLine( pos.x, pos.y + sh, tmp.x, tmp.y + sh );

return tmp.x;
}

bool CDisplayFont::LoadCodepoint( Codepoint_t cp, GlyphInfo_t * out )
{
FT_Error err = 0;
{
return false;
}

out->width = m_fontFace->glyph->bitmap.width;
out->height = m_fontFace->glyph->bitmap.rows;
out->offsetX = m_fontFace->glyph->bitmap_left;
out->offsetY = m_fontFace->glyph->bitmap_top;
out->texture = NULL; // we're not creating the texture yet

float x0 = out->offsetX;
float y0 = out->height - out->offsetY;
float x1 = x0 + out->width;
float y1 = y0 + out->height;
float itw = 1.f / static_cast< float >( m_lTexSize );
float ith = 1.f / static_cast< float >( m_lTexSize );

out->texcoords[ 0 ] = x0 * itw; // left
out->texcoords[ 2 ] = x1 * itw; // right

out->texcoords[ 1 ] = y0 * ith; // top
out->texcoords[ 3 ] = y1 * ith; // bottom

return true;
}

Still pretty satisfied, considering just 1 hour ago, only weird small blocks were being displayed on the screen haha.

Appreciate any help.

##### Share on other sites

Variations in thickness often result from numerical errors in scaling. Please make 110% sure you're not scaling anything, from font description to bitmap, or from bitmap to screen. One way is to get a handle on it is to dump the bitmap you get from the font as rows of text characters, and use a non-proportional font to check. EDIT: You may want to disable anti-aliasing here.

The "g" is drawn incorrectly. The full circle of the letter should rest at the baseline, and the extension at the bottom should be below the baseline. Just look how the "g" is rendered here relative to the other text. Not sure of the details of FreeType any more, but iirc you could have a negative offset wrt to the baseline if you had to start below it. As you can see at https://www.freetype.org/freetype2/docs/tutorial/step2.html the bottom of the letter can be below "origin"

Edited by Alberth

##### Share on other sites
On 1/20/2019 at 5:37 AM, Alberth said:

The "g" is drawn incorrectly. The full circle of the letter should rest at the baseline, and the extension at the bottom should be below the baseline. Just look how the "g" is rendered here relative to the other text. Not sure of the details of FreeType any more, but iirc you could have a negative offset wrt to the baseline if you had to start below it. As you can see at https://www.freetype.org/freetype2/docs/tutorial/step2.html the bottom of the letter can be below "origin"

Yes, I realize that.

Hence the code here

float sy = tmp.y + ( m_nMaxYOffset - glyph->offsetY ) * m_fScaleVert;

And it seems that I fixed the issue with the various widths, until I increased the font size and the same thing happened again.

22 font size

23 font size

Someone else had the same issue and it seemed he fixed it by subtracting the offset from the character T's offset.

Thanks.

##### Share on other sites

The "g" looks like you assume row 0 of the bitmap is always at the baseline, and the bitmap has the same number of rows as the height of the letter. For letters that end below the baseline, this cannot be true.

Instead of randomly trying weird fixes, why not debug your problem? Take the "g", as that's clearly wrong, and look at the numbers you get from the freetype library. Take a piece of paper, and draw where the bitmap box is, according to the documentation and the numbers that you get.

##### Share on other sites
21 hours ago, Alberth said:

The "g" looks like you assume row 0 of the bitmap is always at the baseline, and the bitmap has the same number of rows as the height of the letter. For letters that end below the baseline, this cannot be true.

Instead of randomly trying weird fixes, why not debug your problem? Take the "g", as that's clearly wrong, and look at the numbers you get from the freetype library. Take a piece of paper, and draw where the bitmap box is, according to the documentation and the numbers that you get.

I was able to calculate the baseline with this line of code.

// top of the glyph
int yMax = m_face->bbox.yMax;
// bottom of the glyph
int yMin = m_face->bbox.yMin;

m_nBaseLine = size * yMax / ( yMax - yMin );

After debugging for hours and going to MS Paint to draw it out and make sure my logic was 100% correct render wise, I figured it was probably the texture coords. that were wrong. I am now left with this.

Note: the line on top of the 'g' is offsetY

Not sure how precise that is but its definitely a step in the right direction! I think there is still some issues with the texture coordinates because I can see some slight clipping, but would appreciate any feedback.

Thanks!

##### Share on other sites

I am not sure what you mean with "computing baseline" from a glyph. Normally you pick an Y coordinate as baseline, and use that as base to compute position of all the letter bitmaps. In other words, the other way around.

I'd start with throwing out as much "float" as possible. Bitmap coordinates and font coordinates are all integers, no reason to have floats in there and it eliminates rounding errors. Even in the mapping to screen coordinates, don't scale, only convert the integer pixel coordinates of the corners at the screen to float, since the renderer wants floats.

Letters are specifically designed to be displayed at their original point-size. If you want a bigger or smaller letter, use a different size font. Freetype has anti-aliasing to smooth the edges if you enable it. The renderer can only make things worse if it's not pixel-perfect plotted onto the screen.

As for clipping, hack the bitmap returned by the library, and add a few additional recognizable pixels in the corners. After rendering to the screen take a screenshot, and verify their position.

##### Share on other sites

Don't mean to necro this or go off topic, but does anyone have any experience rendering colored emoji's?

I can render emoji's just fine (using char32_t)

The problem is actually when trying to load a colored font, which I expected this one to be. I've tried 3-4 different fonts that are labeled as colored but FT_HAS_COLOR() seems to always return false on the font..

I am supplying FT_LOAD_COLOR into FT_Load_Char flags, but it doesn't seem to do much. I am expecting pixel_mode to be set to FT_PIXEL_MODE_BGRA as it says in the documentation, but I always get FT_PIXEL_MODE_GRAY.

Any help would be greatly appreciated! Thanks

## Create an account

Register a new account

• ### Game Developer Survey

We are looking for qualified game developers to participate in a 10-minute online survey. Qualified participants will be offered a \$15 incentive for your time and insights. Click here to start!

• 17
• 23
• 13
• 20