4
\$\begingroup\$

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.

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

}
\$\endgroup\$
  • 1
    \$\begingroup\$ It looks like you get either wrong character widths or kerning values. Did you try disabling the kerning altogether to check if you get correct character widths this way? \$\endgroup\$ – bummzack Jan 10 '11 at 9:18
  • \$\begingroup\$ Yes I did, I am not getting the correct character widths. how can i properly obtain those? \$\endgroup\$ – jack Jan 10 '11 at 16:06
  • \$\begingroup\$ Sorry, my comment was probably ambiguous. What I meant is: If you disable the kerning (eg. the whole if(c != 0) block). Do you still get these overlapping characters? \$\endgroup\$ – bummzack Jan 11 '11 at 8:12
  • 1
    \$\begingroup\$ Also, please don't ask the same question on Stack Overflow and here (stackoverflow.com/questions/4601217/…). \$\endgroup\$ – user744 Jan 11 '11 at 11:10
  • 1
    \$\begingroup\$ Justification for vote-to-close as too localized: The author hasn't been here since a week after the question, it's "fix my code" in a very specific case, not enough information is provided, and tools to solve the general problem are widely available and referenced in other answers. \$\endgroup\$ – user744 Mar 1 '11 at 23:35
0
\$\begingroup\$

Like bluescrn and Jari have suggested, I'd say go with bmfont if you can.

But if you want an example that just draws text, here's a snippet I was toying with some months back. Part are surely borrowed from somewhere (the PNG codec writer), but I have no idea where.

Good luck!

#include <Windows.h>
#include <Wingdi.h>
#include <gdiplus.h>
#include <Gdiplusgraphics.h>
using namespace Gdiplus;

extern int MyGenTexture[512*512];
int MyGenTexture[512*512];

int GetEncoderClsid(const WCHAR* format, CLSID* pClsid)
{
   UINT  num = 0;          // number of image encoders
   UINT  size = 0;         // size of the image encoder array in bytes

   ImageCodecInfo* pImageCodecInfo = NULL;

   GetImageEncodersSize(&num, &size);
   if(size == 0)
      return -1;  // Failure

   pImageCodecInfo = (ImageCodecInfo*)(malloc(size));
   if(pImageCodecInfo == NULL)
      return -1;  // Failure

   GetImageEncoders(num, size, pImageCodecInfo);

   for(UINT j = 0; j < num; ++j)
   {
      if( wcscmp(pImageCodecInfo[j].MimeType, format) == 0 )
      {
         *pClsid = pImageCodecInfo[j].Clsid;
         free(pImageCodecInfo);
         return j;  // Success
      }    
   }

   free(pImageCodecInfo);
   return -1;  // Failure
}

extern void MakeTexture();
void MakeTexture() {
    HDC myDC = CreateCompatibleDC(NULL);
    //HBITMAP GenTexture = CreateCompatibleBitmap( Context, 512, 512 );

    BITMAPINFOHEADER myInfoHeader = {
        sizeof(BITMAPINFOHEADER),
        512,
        -512, // Negative, to make it top down //
        1,
        32,
        BI_RGB,
        0, // Size of compressed data //
        4096, // Pixels per meter //
        4096,
        0,
        0
        };

/*  HBITMAP myTexture = CreateDIBitmap(
        myDC,
        &myInfoHeader,
        NULL,
        NULL,
        NULL,
        DIB_RGB_COLORS
        );
*/

    BITMAPINFO myInfo = {
        myInfoHeader,
        0
        };

    int* Data;

    HBITMAP myTexture = CreateDIBSection(
        myDC,
        &myInfo,
        DIB_RGB_COLORS,
        (void**)&Data,
        NULL,
        NULL
        );

    SelectObject( myDC, myTexture );

    GdiplusStartupInput gdiplusStartupInput;
    ULONG_PTR           gdiplusToken;
    // Initialize GDI+.
    GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL);

    {
        Graphics g( myDC, myTexture );
        SolidBrush brush( Color(255,255,255,255) ); 
        FontFamily fontFamily( L"Times New Roman" );
        Font font( &fontFamily, 48, FontStyleRegular, UnitPixel );

        for( int idx = 0; idx < 512*512; idx++ ) {
            Data[idx] = 0x00FFFFFF;
        }


        //g.Clear( Color(0,255,255,255) );
        g.DrawString(L"Using \"Technology\", i.e.",-1,&font,PointF(0,20),&brush);
        g.DrawString(L"GDI+, I have created a",-1,&font,PointF(0,70),&brush);
        g.DrawString(L"texture from system",-1,&font,PointF(0,120),&brush);
        g.DrawString(L"installed fonts! That",-1,&font,PointF(0,170),&brush);
        g.DrawString(L"means international",-1,&font,PointF(0,220),&brush);
        g.DrawString(L"characters!",-1,&font,PointF(0,270),&brush);
        g.DrawString(L"",-1,&font,PointF(0,320),&brush);
        g.DrawString(L"      スマイルズ ",-1,&font,PointF(0,370),&brush);
        g.Flush();


        for( int idx = 0; idx < 512*512; idx++ ) {
            MyGenTexture[idx] = Data[idx];
        }


        // Write File //
        Bitmap OutBitmap(myTexture,NULL);

        CLSID encoderClsid;
        GetEncoderClsid(L"image/png", &encoderClsid);
        Status stat = OutBitmap.Save(L"Awesome.png", &encoderClsid, NULL);
    }

    GdiplusShutdown(gdiplusToken);


    DeleteObject( myTexture );
    //DeleteObject(GenTexture);
    DeleteDC(myDC);
}
| improve this answer | |
\$\endgroup\$
-1
\$\begingroup\$

You could always give this a try: http://www.angelcode.com/products/bmfont/

It generates nicely-packed textures of bitmap characters, and an .xml file of all the UV/spacing data. Results are generally very good.

| improve this answer | |
\$\endgroup\$
  • 2
    \$\begingroup\$ He explicitly says "I am trying to do this without using external libraries such as angel bitmap tool or freetype.", but yes, I would also recommend using the angelcode bitmap font tool. =) \$\endgroup\$ – Jari Komppa Jan 11 '11 at 11:18