bitmap font system design

Started by
2 comments, last by Anon Mike 18 years ago
This isn't stricly about games, but since it's about bitmap fonts, I figure that more than a couple of people here would be able to help by giving me a nudge. I'm having a couple of problems attempting to implement a bitmap font system. I have an IVideoDriver class (OGL, DX, although I'm only implementing OGL at the moment) and my bitmap font class seperated into IBitmapFont and COpenGLBitmapFont:

/**
 * Class representing the basics of a bitmap font.
 */
class IBitmapFont	:	public IMBase
{
private:

	std::string m_name;	///< The name of the font
	bool m_bold;		///< If the font is bold
	bool m_italic;		///< If the font is italic
	bool m_underlined;	///< If the font is underlined

	int m_charWidths[96];	///< The widths of each printable character

	HDC m_hdc;		///< The hardware device context 
	
public:

	/**
	 * Constructor
	 * \param hdc The hardware device context
	 * \param name The font name we want
	 * \param italic Whether the font is italic
	 * \param bold Whether the font is bold
	 * \param underlined Whether the font is underlined
	 */
	IBitmapFont(HDC hdc, const char* name, bool italic, bool underlined, bool bold)
		:	m_hdc(hdc), m_name(name), m_italic(italic), m_bold(bold), m_underlined(underlined)
	{
		// Get an array of widths for a range of characters
		if( !GetCharWidth32(m_hdc, 32, 127, m_charWidths) )
			util::Message::print("IBitmapFont:: Unable to load character widths for font \"%s\"", name);
	}

	/**
	 * Get the width of a particular character
	 * \param c The character to get the width of
	 */
	int getCharWidth(char c)
	{
		return m_charWidths[c-32];	// because we're not using the first 32 characters (non-printable)
	}


};


/**
 * Represents a bitmap font in open gl.
 */
class COpenGLBitmapFont	:	public video::IBitmapFont
{
private:

	unsigned int m_fontList;	///< The opengl display list id for the bitmap font

public:

	/**
	 * Constructor
	 * \param hdc The HDC for the window
	 * \param name The font name we want
	 * \param italic Whether the font is italic
	 * \param bold Whether the font is bold
	 * \param underlined Whether the font is underlined
	 */
	COpenGLBitmapFont(HDC hdc, const char* name, bool italic, bool underlined, bool bold )
		:	IBitmapFont(hdc, name, italic, underlined, bold)
	{	}

	/**
	 * Create the font
	 * \param hdc The hardware device context for creating the font
	 */
	bool createFont()
	{
		HFONT font;	// Window font id
		HFONT oldfont;	// Used for good house keeping

		m_fontList = glGenLists(96);	// Storage for 96 characters

		font = CreateFont(	-15,	// Height of font
					8,	// Width of font
					0,	// Angle of escapement
					0,	// Orientation Angle
					FW_NORMAL,// Font weight
					m_italic,// Italic
					m_underlined,// Underline
					m_bold,	// Strikeout
					ANSI_CHARSET,	// Character set identifier
					OUT_TT_PRECIS,	// Output precision
					CLIP_DEFAULT_PRECIS,// Clipping precision
					ANTIALIASED_QUALITY,// Output quality
					FF_DONTCARE|DEFAULT_PITCH,// Family and pitch
					"Arial");// Font name

		oldfont = (HFONT) SelectObject(hdc, font);	// Selects the font we want
		wglUseFontBitmaps(hdc, 32, 96, m_fontList);	// Builds 96 characters starting at character 32
		SelectObject(hdc, oldfont);	// Selects the font we want
		DeleteObject(font);		// Delete the font
	}


};

That's it for the moment, but I'm having a problem with the printing of the text. I initially thought that I could call a function on the bitmap font object, but then I'd have to include the raster position and unless I wanted to always pass a pointer, I'd need a pointer to the VideoDriver inside the bitmap font class. I think that would be going a little too far and too inelegant. I was just stuck with a thought. What if I just kept all of the created bitmap font objects inside the VideoDriver class and whenever I called "createBitmapFont", it would return a handle (integer, whatever). Then, I could just keep with calling the video driver to draw text. I think that I'm more inclined to the latter, but I am looking for any better ideas. Also, just say a have a whole lot of fonts and I'm drawing text with each of them in every rendering frame. I'm using windows, as you could probably tell from the code. When using SelectObject, how quick is it to change fonts? Is it intensive either in time or memory?
[size="2"][size=2]Mort, Duke of Sto Helit: NON TIMETIS MESSOR -- Don't Fear The Reaper
Advertisement
Quote:Original post by Endar
Also, just say a have a whole lot of fonts and I'm drawing text with each of them in every rendering frame. I'm using windows, as you could probably tell from the code. When using SelectObject, how quick is it to change fonts? Is it intensive either in time or memory?


SelectObject and quickness? Are you calling createFont once per frame or something? Since you're using display lists you don't need to do that.

Also, another thing strange is your calculating widths -> from the constructor even before the font is created and selected into the DC??? That might load the wrong widths.

I also make the font class just a glyph wrapper as well with no rendering support. It's messy if you do it otherwise, especially if you have multiple viewports. The font class would be a friend of the video class and the video class would do the rendering and handle correct placement in whatever viewport your rendering in.

On a personal note, I also don't use wglUseFontBitmaps. I noticed it adds too much spacing to the height of the glyphs for my taste so I make a monochrome bitmap and call glBitmap from a compiled display list myself.
Quote:Original post by yadango
SelectObject and quickness? Are you calling createFont once per frame or something? Since you're using display lists you don't need to do that.

I think I made a mistake in my understanding. When I change fonts I don't need to call 'SelectObject' because I've made a display list with the characters in it.

Quote:Original post by yadango
Also, another thing strange is your calculating widths -> from the constructor even before the font is created and selected into the DC??? That might load the wrong widths.

Yeah, I'm still in the middle of writing it and haven't actually run it yet. Thanks.
[size="2"][size=2]Mort, Duke of Sto Helit: NON TIMETIS MESSOR -- Don't Fear The Reaper
Quote:Original post by Endar
Also, just say a have a whole lot of fonts and I'm drawing text with each of them in every rendering frame. I'm using windows, as you could probably tell from the code. When using SelectObject, how quick is it to change fonts? Is it intensive either in time or memory?


SelectObject itself doesn't really do anything so it's pretty speedy. All the work happens the first time you use a given instance of a font. GDI maintains a cache of glyph metrics and bitmaps so once you get the cache going it's not to bad. It depends on your exact usage pattern of course.
-Mike

This topic is closed to new replies.

Advertisement