I am generating a bitmap, however, I am not sure on how to render the UV's and placement. I had a thread like this once before, but it was too loosely worded as to what I was looking to do.
What I am doing right now is creating a large 1024x1024 image with characters evenly placed every 64 pixels. Here is an example of what I mean. I then save the bitmap X/Y information to a file (which is all multiples of 64).
However, I am not sure how to properly use this information and bitmap to render. This falls into two different categories, UV generation and kerning. Now I believe I know how to do both of these, however, when I attempt to couple them together I will get horrendous results.
For example, I am trying to render two different text arrays, "123" and "njfb". While ignoring the texture quality (I will be increasing the texture to provide more detail once I fix this issue), here is what it looks like when I try to render them.
http://img64.imageshack.us/img64/599/badfontrendering.png
Now for the algorithm. I am doing my letter placement with both GetABCWidth and GetKerningPairs. I am using GetABCWidth for the width of the characters, then I am getting the kerning information for adjust the characters.
Does anyone have any suggestions on how I can implement my own bitmap font renderer? I am trying to do this without using external libraries such as angel bitmap tool or freetype. I also want to stick to the way the bitmap font sheet is generated so I can do extra effects in the future.
Rendering Algorithm
for(U32 c = 0, vertexID = 0, i = 0; c < numberOfCharacters; ++c, vertexID += 4, i += 6)
{
ObtainCharInformation(fontName, m_Text[c]);
letterWidth = (charInfo.A + charInfo.B + charInfo.C) * scale;
if(c != 0)
{
DWORD BytesReq = GetGlyphOutlineW(dc, m_Text[c], GGO_GRAY8_BITMAP, &gm, 0, 0, &mat);
U8 * glyphImg= new U8[BytesReq];
DWORD r = GetGlyphOutlineW(dc, m_Text[c], GGO_GRAY8_BITMAP, &gm, BytesReq, glyphImg, &mat);
for (int k=0; k<nKerningPairs; k++)
{
if ((kerningpairs[k].wFirst == previousCharIndex) && (kerningpairs[k].wSecond == m_Text[c])) {
letterBottomLeftX += (kerningpairs[k].iKernAmount * scale);
break;
}
}
letterBottomLeftX -= (gm.gmCellIncX * scale);
}
SetVertex(letterBottomLeftX, 0.0f, zFight, vertexID);
SetVertex(letterBottomLeftX, letterHeight, zFight, vertexID + 1);
SetVertex(letterBottomLeftX + letterWidth, letterHeight, zFight, vertexID + 2);
SetVertex(letterBottomLeftX + letterWidth, 0.0f, zFight, vertexID + 3);
zFight -= 0.001f;
float BottomLeftX = (F32)(charInfo.bitmapXOrigin) / (float)m_BitmapWidth;
float BottomLeftY = (F32)(charInfo.bitmapYOrigin + charInfo.charBitmapHeight) / (float)m_BitmapWidth;
float TopLeftX = BottomLeftX;
float TopLeftY = (F32)(charInfo.bitmapYOrigin) / (float)m_BitmapWidth;
float TopRightX = (F32)(charInfo.bitmapXOrigin + charInfo.B - charInfo.C) / (float)m_BitmapWidth;
float TopRightY = TopLeftY;
float BottomRightX = TopRightX;
float BottomRightY = BottomLeftY;
SetTextureCoordinate(TopLeftX, TopLeftY, vertexID + 1);
SetTextureCoordinate(BottomLeftX, BottomLeftY, vertexID + 0);
SetTextureCoordinate(BottomRightX, BottomRightY, vertexID + 3);
SetTextureCoordinate(TopRightX, TopRightY, vertexID + 2);
/// index setting
letterBottomLeftX += letterWidth;
previousCharIndex = m_Text[c];
}