DirectX 9 Customs Fonts

Started by
7 comments, last by Nik02 14 years, 1 month ago
Hi, I have to draw text using a lookup table from a bitmap. I do not want to use D3DXFont since I have to apply an outline to each caracters after drawing it on the bitmap with TextOut API. I will use GDI+ for the Outline. I have use the following code : http://www.gamedev.net/community/forums/viewreply.asp?ID=1098396 The problem is that the contour of the letter is not very precise. In conclusion it is not pretty. I have save the bitmap generated on hard disk and then opened it with MSPaint and the letter a perfectly smooth, I mean this is not the same result as what I have on the screen with Direct3D... Here is a screenshot : http://i175.photobucket.com/albums/w155/Feltar/TextOutD3D.png What can I do to improve the quality ? Or what do I have to do to improve the rendering quality ? Best regards PS : Cross posting : http://forums.xna.com/forums/p/48445/290551.aspx#290551 [Edited by - Erakis on February 25, 2010 11:35:32 AM]
Advertisement
Hi,

Here is how I'm rendering text to the Direct3D surface. First of all I'm pre-rendering all the font characters into a 32bpp bitmap.

Here is the result : http://i175.photobucket.com/albums/w155/Feltar/Direct3DLookUpFont.png

To add an outline to each caracters I'm using GDIPlus :

Graphics graphics(hdc);   graphics.SetSmoothingMode(SmoothingModeAntiAlias);   graphics.SetInterpolationMode(InterpolationModeHighQualityBicubic);   GraphicsPath path;   FontFamily fontFamily(m_szFontName);   StringFormat strformat;     // For each caracters loop ... path.Reset();   s = path.AddString(szTempString, 1, &fontFamily, FontstyleRegular, 32, PointF(unTextOutX, unTextOutY), &strformat);   Color cOutlineColor;   cOutlineColor.SetFromCOLORREF( outlineColor );   Pen pen(cOutlineColor, 2);   pen.SetLineJoin(LineJoinRound);   s = graphics.DrawPath(&pen, &path);   Color cTextColor;   cTextColor.SetFromCOLORREF(color);   SolidBrush brush(cTextColor);   graphics.FillPath(&brush, &path);  


Now from this Bitmap, I create a Direct3D texture and I copy transfert all the pixels. But during the transfert I need to simulate the alpha. I other words, I need to set an alpha = 0 for each pixel of the background and set an alpha of 255 to all other. Here is how I do it :

DWORD* pDestData = (DWORD*)d3dLockedRect.pBits;     DWORD dwTransparentColor = ((backgroundColor >> 16) & 0x000000ff) |                              ((backgroundColor << 16) & 0x00ff0000) |                              (backgroundColor & 0x0000ff00);     pBitmapBits += m_unTextureWidth * (m_unTextureHeight - 1);   for (UINT y = 0; y < m_unTextureHeight; ++y )   {       DWORD* pRow = pBitmapBits;       for (UINT k = 0;  k < m_unTextureWidth; ++k, ++pRow )       {           if (*pRow == dwTransparentColor)           {               *pRow = 0x00000000;           }           else          {               *pRow |= 0xff000000;           }       }                  memcpy(pDestData, pBitmapBits, m_unTextureWidth * sizeof(DWORD));         pDestData += ( d3dLockedRect.Pitch / 4 );       pBitmapBits -= m_unTextureWidth;   }        m_CharactersTexture->UnlockRect( 0 );


And then from the texture I create a SPRITE. The result without the Outline is fair but not perfect as if I was writing text over a bitmap using MSPaint. But as you can see in the preceding image "Direct3DLookUpFont.png" some pixels of the background left mixed with those of the outline.

How can I get a better transparency ?


I feel the way I simulate the alpha value is not good... Else is someone here have an idea on how to better proceed, I am really desperate. This is 1 week as I try to display text with outline on a Direct3D surface.

Best regards
Your current technique is formally called "color keying". It is not widely used in modern text rendering because - as you can see - the edges of the opacity are aliased.

GDI+ supports real alpha channels. If you create the temp bitmap with alpha, you can just copy the values to your D3D texture. Before drawing your text, be sure to clear the alpha channel to 0 so you actually get a transparent background.

Niko Suni

Also, I note that you create the Graphics object against a HDC. The HDC is a classical Win32 device context which has poor native alpha channel support (though it can support some simple alpha ops on XP and later).

For the temp bitmap (to which you initially draw the text), consider using the GDI+ Bitmap class instead. It is very robust and you can create your Graphics object directly against it.

Niko Suni

Sorry for my ignorance, but how to realize a bitmap with real alpha channels ?

Also if I'm using bitmap that support real alpha channels, will I get better result ? I mean sharpness edges without jagged pixels ?

So If I well understand I proceeed the same way but I use a GDI+ Bitmap class instead. And just before creating the texture I set the alpha value of each pixel having the same color as my background to 0 ?

If I use the GDI+ Bitmap class, I presume that I create the graphic object from the GDI+ Bitmap (PixelFormat32bppARGB ) ?

Thank you very much, it's very appreciated that you help me
Best regards
To create a Bitmap with an alpha channel, just specify a pixel format that includes an alpha component when using the Bitmap ctor.

If you use a proper alpha channel, the antialiasing of the text carries through your pipeline. While it doesn't magically make the text sharper (increasing resolution will), it is more legible.

The Graphics object (which you can use to draw to a Bitmap, since Bitmap derives from Image) has a Clear method that you can use to init the pixels to a given value. This applies to the alpha channel too.

First, you should clear the Bitmap. Then, you draw your antialiased text into it. Finally, copy all the data (including the alpha as is) from the Bitmap to the D3D texture. You don't need any manual per-pixel processing here.

Niko Suni

Forgot to mention that you can control the text rendering method by using Graphics::SetTextRenderingHint. I think that antialiasing is off by default.

Niko Suni

Hi,

Nik02 let me tell you a thousand thanks you've made my day :)

The result is from far better quality than the traditionnal GDI.

And I no longer need to manually set the alpha component as I did before. A simple "memcpy" call do the trick and all the alpha values are maintained from the bitmap to the texture to allow transparancy. Exactly as you said. You're a pro !

Best regards
Glad I could help :)

Niko Suni

This topic is closed to new replies.

Advertisement