Sign in to follow this  
jherik0

xadvance values seem wrong

Recommended Posts

mainly they seem to be consistently smaller than the character width which seems wrong.

 

i feel i am using them as documented and the same as other examples, but when rendering there is clearly something wrong in the x direction only.

 

the crucial bit of code that I have written looks like this:

 

const BMCharData& xCharData = **ppxCharData;
mfXCursor += xCharData.mfAdvanceX * fScale;
const BMKerningPair** ppxKerningData = mpxFont->mxKerningMap.Find( Render::Font::KerningHash( wcLastChar, wcCurrentChar ) );
if( ppxKerningData )
{
    mfXCursor += ( **ppxKerningData ).mfKerningAmount * fScale;
}
pxCurrentGeometry->AddCharacter( *mpxFont, fScale, mfXCursor, mfYCursor, wcCurrentChar );
wcLastChar = wcCurrentChar;
the visual result comes out looking like this (in this case no kerning hints are present to be applied, so the dodgy x positions are resulting entirely from the xadvance data):
 
OafmbQm.png
 
to make it clear if it is not it should be reading 182.45 fps and RT: 0.8 ms
 
does anyone have any suggestions on why this may be the case? am i wrong to interpret xadvance as using the same scale factor as the x, y, width, height and x and y offsets?
 
as a dumb guess, maybe i am rendering the quads backwards with the uvs flipped in the u direction - although i wouldn't expect the kind of overlap i see here to result from that (smaller characters seem /further/ offset to the left - but my internal visualisation may well be a complete fiction). i will try this quickly... but that would be extremely odd. none of the other code i've found and looked at for reference seems to do that. (although y is inverted, which seems to be the way)

Share this post


Link to post
Share on other sites

for the record it does indeed look better when i flip the relative position of the character geometry in x:

 

bArvwJa.png

 

it is still clearly a bit wrong though.

 

flipping the xoffset looks much better, but still a bit wrong imo:

 

wAaCt5g.png

 

my intuition is that these numbers should not be smaller than the character widths - however given the nature of the xoffset this thinking might be very wrong.

 

is it possible that my choice of font simply lacks enough kerning hints to make the 2 next to the 1 not look completely wrong? (its open sans btw)

 

again thanks in advance to any potential replies.

Share this post


Link to post
Share on other sites

for completeness the code adding vertices to the vertex buffers now looks like this:

        const BMCharData& xCharData = **ppxChar;
        const float fInnerX = fX - xCharData.mfOffsetX * fScale;
        const float fInnerY = fY - xCharData.mfOffsetY * fScale;
        const float fScaledWidth = xCharData.mfWidth * fScale;
        const float fScaledHeight = xCharData.mfHeight * fScale;
        FontVertex axVertices[ 4 ] =
        {
	    { fInnerX, fInnerY,
                xCharData.mfUX + xCharData.mfWidth, xCharData.mfVY },
            { fInnerX, fInnerY - fScaledHeight,
                xCharData.mfUX + xCharData.mfWidth, xCharData.mfVY + xCharData.mfHeight },
            { fInnerX - fScaledWidth, fInnerY - fScaledHeight, xCharData.mfUX,
                xCharData.mfVY + xCharData.mfHeight },
            { fInnerX - fScaledWidth, fInnerY,
                xCharData.mfUX, xCharData.mfVY },
        };

	for( int i = 0; i < 4; ++i )
	{
	    maxVertices.Append( axVertices[ i ] );
	}

Share this post


Link to post
Share on other sites

Sounds like your actual xadvance values are wrong. Here's a Verdana at 64 points:

char id=65   x=0     y=133   width=36    height=38    xoffset=0     yoffset=14    xadvance=36    page=0  chnl=15
char id=66   x=310   y=129   width=31    height=38    xoffset=4     yoffset=14    xadvance=36    page=0  chnl=15
char id=67   x=218   y=50    width=33    height=40    xoffset=2     yoffset=13    xadvance=36    page=0  chnl=15
char id=68   x=107   y=132   width=34    height=38    xoffset=4     yoffset=14    xadvance=40    page=0  chnl=15
char id=69   x=29    y=172   width=27    height=38    xoffset=4     yoffset=14    xadvance=33    page=0  chnl=15
char id=70   x=84    y=172   width=26    height=38    xoffset=4     yoffset=14    xadvance=30    page=0  chnl=15

Share this post


Link to post
Share on other sites

As you're just showing bits and pieces of your code it's hard to know but it seems to me that you're using moving the cursor before drawing the quad using the xadvance of the current character.

 

What you should be doing is to draw the quad of the current character at the current position, then move the cursor with the xadvance of that character.

 

 

In my CFont writer class the code looks like this:

 

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

 

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this