BMfont loader

Started by
6 comments, last by Papadopol 11 years, 8 months ago
Hello. I'm trying to read and render some text in DirectX using BMfont.
So far I managed to load characters and render them like this: I create quads based on x,y, wifth and height.
I map over the texture creating UVs based on x,y,width and height of an character.
But I know know how to move up and down characters like "j" or "g" to align corectly with other characters. So far I've read the kerning are used for spacing between characters but on the X axis. What about the Y axis ?

font.jpg
Advertisement
See this post for a description of the BMFont config properties: http://www.gamedev.net/topic/284560-bmfont-and-how-to-interpret-the-fnt-file/page__p__2785731#entry2785731

You don't need kerning to get something decent, kerning is just icing on the cake. You just need to offset the characters vertically by their xoffset and yoffset when you draw them. By the way it looks, I think you're probably just using the width of the character and placing the next one directly after it without taking xoffset and yoffset into account.

Between Scylla and Charybdis: First Look <-- The game I'm working on

Object-Oriented Programming Sucks <-- The kind of thing I say

You may also be interested in taking a look at my implementation of a font renderer that uses the BMFont format. It's open source, in case you wish you use it directly.

https://actb.svn.sourceforge.net/svnroot/actb/trunk/source/gfx/

The relevant code is in the acgfx_font.cpp.

Regards,
Andreas

AngelCode.com - game development and more - Reference DB - game developer references
AngelScript - free scripting library - BMFont - free bitmap font generator - Tower - free puzzle game

So, xoffset is for spacing between characters, yoffset for moving characters down (for example j,g) and kerning to space some characters that doesnt use default offset ?

So, xoffset is for spacing between characters, yoffset for moving characters down (for example j,g) and kerning to space some characters that doesnt use default offset ?

xoffset and yoffset are just the general offsets for each character, yes, and usually works well enough for typesetting by itself.

Kerning is just an additional xoffset for character pairs that doesn't look good with the default offsets. Note that it applies to pairs of characters. Only the second character in the pair is actually moved, but the kerning is dependent on both characters. For example, the P and J pair typically has a kerning value to move the hook of the J under the P to lessen the apparent gap between them, but there is typically no kerning value between J and P since the stems of both characters already has a decent gap.

Kerning is not really necessary unless you're aiming for higher quality typesetting. You can stay away from it to begin with and implement it at a later stage once you have the basic typesetting working.
I dont manage to do it. Its probably because I have quads that are not the same ? Im making gaps between characters with Xoffset but my characters are quads in the size of the UV I map.
Also the character id coresponds with a letter that I create in char by substractin 32;
for ex:

char char[0]= 'a' - 32;

char[0] will draw corectly lowercase a;
Here's the relevant code from my font renderer that draws each characters and moves the cursor:


void CFont::InternalWrite(float x, float y, float z, const char *text, int count, float spacing)
{
if( render->GetGraphics() == 0 )
return;
int page = -1;
render->Begin(RENDER_QUAD_LIST);
y += scale * float(base);
for( int n = 0; n < count; )
{
int charId = GetTextChar(text, n, &n);
SCharDescr *ch = GetChar(charId);
if( ch == 0 ) ch = &defChar;
// Map the center of the texel to the corners
// in order to get pixel perfect mapping
float u = (float(ch->srcX)+0.5f) / scaleW;
float v = (float(ch->srcY)+0.5f) / scaleH;
float u2 = u + float(ch->srcW) / scaleW;
float v2 = v + float(ch->srcH) / scaleH;
float a = scale * float(ch->xAdv);
float w = scale * float(ch->srcW);
float h = scale * float(ch->srcH);
float ox = scale * float(ch->xOff);
float oy = scale * float(ch->yOff);
if( ch->page != page )
{
render->End();
page = ch->page;
render->GetGraphics()->SetTexture(pages[page]);
render->Begin(RENDER_QUAD_LIST);
}
render->VtxColor(color);
render->VtxData(ch->chnl);
render->VtxTexCoord(u, v);
render->VtxPos(x+ox, y-oy, z);
render->VtxTexCoord(u2, v);
render->VtxPos(x+w+ox, y-oy, z);
render->VtxTexCoord(u2, v2);
render->VtxPos(x+w+ox, y-h-oy, z);
render->VtxTexCoord(u, v2);
render->VtxPos(x+ox, y-h-oy, z);
x += a;
if( charId == ' ' )
x += spacing;
if( n < count )
x += AdjustForKerningPairs(charId, GetTextChar(text,n));
}
render->End();
}


The quad has the size of the UV that you map, just as you say. The offsetX and offsetY should be added to the current position when drawing the quad, but they do no affect the position of the next character. The position of the next character is determined from the xAdvance and possible kerning pair adjustment.

In short:

for each character in text do
- tmpPos = currentPos
- tmpPos += (offsetX, offsetY)
- draw quad at tmpPos (quad is defined by x, y, w, h in font description)
- currentPos += xAdvance
- if exist kerning for this character with next character then currentPos += kerning


I hope that helps.

Regards,
Andreas

AngelCode.com - game development and more - Reference DB - game developer references
AngelScript - free scripting library - BMFont - free bitmap font generator - Tower - free puzzle game

Thank you very much for taking your time and writing this code. I will try it soon and reply back.
le:
It worked as a charm thanks to your pseudocode explanation.
Thanks again.

This topic is closed to new replies.

Advertisement