// BitmapFontFace: A class to store a font in which the glyphs are stored in bitmaps. #pragma once // This namespace #include "FontFaceMetrics.h" // Dan std #include #include #include #include using dan::Error; // Boost #include using boost::scoped_array; #include // C++ std #include #include namespace dan { struct BitmapFontGlyph // Where to find the graphic for a single character // // (This is only used by BitmapFontFace but isn't declared within it as it doesn't need to // use BitmapFontFace's template parameters) { unsigned int bitmapNo; // Which bitmap of the BitmapFontFace contains the glyph of this character dan::math::Rect2I rect; // The position and size on the bitmap of the character's glyph dan::math::Vector2I bearing; // Distance from the drawing pen position to where the top-left of the glyph should be dan::math::Vector2I advance; // The number of pixels that the drawing pen position should be moved // after printing this character, to be ready for the next one BitmapFontGlyph(unsigned int i_bitmapNo, const dan::math::Rect2I & i_rect, const dan::math::Vector2I & i_bearing, const dan::math::Vector2I & i_advance) : bitmapNo(i_bitmapNo), rect(i_rect), bearing(i_bearing), advance(i_advance) {} }; typedef std::map BitmapFontCharmap; // Represents a character map, // ie. a full alphabet of mappings from character code numbers to glyphs. // This collection of mappings is also known as a character encoding. // // (This is only used by BitmapFontFace but isn't declared within it as it doesn't need to // use BitmapFontFace's template parameters) template class BitmapFontFace { // + Shared part {{{ protected: struct Shared { std::vector< Bitmap > m_bitmaps; std::vector m_charmaps; float m_emHeight; FontFaceMetrics m_metrics; unsigned int m_replacementForMissingCharCode = 0; // + Construction {{{ Shared(float i_emHeight = 1, const FontFaceMetrics & i_metrics = FontFaceMetrics()) : m_emHeight(i_emHeight) , m_metrics(i_metrics) // Construct with no bitmaps or charmaps {} Shared(const std::vector< Bitmap > & i_bitmaps, const std::vector & i_charmaps, float i_emHeight = 1, const FontFaceMetrics & i_metrics = FontFaceMetrics()) : m_emHeight(i_emHeight) , m_metrics(i_metrics) // Construct with multiple bitmaps and multiple charmaps { m_bitmaps.assign(i_bitmaps.begin(), i_bitmaps.end()); m_charmaps.assign(i_charmaps.begin(), i_charmaps.end()); } Shared(const Bitmap & i_bitmap, const std::vector & i_charmaps, float i_emHeight = 1, const FontFaceMetrics & i_metrics = FontFaceMetrics()) : m_emHeight(i_emHeight) , m_metrics(i_metrics) // Construct with single bitmap and multiple charmaps // (bitmap specified in Bitmap object) { m_bitmaps.push_back(i_bitmap); m_charmaps.assign(i_charmaps.begin(), i_charmaps.end()); } Shared(PixelType * i_srcBitmap_pixels, unsigned int i_srcBitmap_width, unsigned int i_srcBitmap_height, const std::vector & i_charmaps, float i_emHeight = 1, const FontFaceMetrics & i_metrics = FontFaceMetrics()) : m_emHeight(i_emHeight) , m_metrics(i_metrics) // Construct with single bitmap and multiple charmaps // (bitmap specified as buffer, width and height) { m_bitmaps.push_back(Bitmap(i_srcBitmap_pixels, i_srcBitmap_width, i_srcBitmap_height)); m_charmaps.assign(i_charmaps.begin(), i_charmaps.end()); } Shared(const std::vector & i_charmaps, float i_emHeight = 1, const FontFaceMetrics & i_metrics = FontFaceMetrics()) : m_emHeight(i_emHeight) , m_metrics(i_metrics) // Construct without any bitmaps stored (class stores font metadata only) { m_charmaps.assign(i_charmaps.begin(), i_charmaps.end()); } // + }}} }; boost::shared_ptr m_shared; // + }}} // + Construction {{{ public: BitmapFontFace(float i_emHeight = 1, const FontFaceMetrics & i_metrics = FontFaceMetrics()) : m_shared(new Shared(i_emHeight, i_metrics)) // Construct with no bitmaps or charmaps {} BitmapFontFace(const std::vector< Bitmap > & i_bitmaps, const std::vector & i_charmaps, float i_emHeight = 1, const FontFaceMetrics & i_metrics = FontFaceMetrics()) : m_shared(new Shared(i_bitmaps, i_charmaps, i_emHeight, i_metrics)) // Construct with multiple bitmaps and multiple charmaps {} BitmapFontFace(const Bitmap & i_bitmap, const std::vector & i_charmaps, float i_emHeight = 1, const FontFaceMetrics & i_metrics = FontFaceMetrics()) : m_shared(new Shared(i_bitmap, i_charmaps, i_emHeight, i_metrics)) // Construct with single bitmap and multiple charmaps // (bitmap specified in Bitmap object) {} BitmapFontFace(PixelType * i_srcBitmap_pixels, unsigned int i_srcBitmap_width, unsigned int i_srcBitmap_height, const std::vector & i_charmaps, float i_emHeight = 1, const FontFaceMetrics & i_metrics = FontFaceMetrics()) : m_shared(new Shared(i_srcBitmap_pixels, i_srcBitmap_width, i_srcBitmap_height, i_charmaps, i_emHeight, i_metrics)) // Construct with single bitmap and multiple charmaps // (bitmap specified as buffer, width and height) {} BitmapFontFace(const std::vector & i_charmaps, float i_emHeight = 1, const FontFaceMetrics & i_metrics = FontFaceMetrics()) : m_shared(new Shared(i_charmaps, i_emHeight, i_metrics)) // Construct without any bitmaps stored (class stores font metadata only) {} // + }}} // + Bitmaps {{{ const std::vector< Bitmap > & bitmaps() const { return m_shared->m_bitmaps; } std::vector< Bitmap > & bitmaps() { return m_shared->m_bitmaps; } //void releaseBitmaps() //{ // m_bitmaps.clear(); //} // + }}} // + Charmaps {{{ const std::vector & charmaps() const { return m_shared->m_charmaps; } unsigned int charmap_count() const { return m_shared->m_charmaps.size(); } unsigned int charmap_charCount() const { return m_shared->m_charmaps.front().size(); } // + }}} // + Metrics {{{ unsigned int emHeight() const { return m_shared->m_emHeight; } FontFaceMetrics & metrics() const { return m_shared->m_metrics; } // + }}} // + Get details of a single char {{{ unsigned int replacementForMissingCharCode() const { return m_shared->m_replacementForMissingCharCode; } void replacementForMissingCharCode(unsigned int i_charCode) const { m_shared->m_replacementForMissingCharCode = i_charCode; } const BitmapFontGlyph & getGlyph(unsigned int i_charmapNo, unsigned int i_charCode) const { if (i_charmapNo >= m_shared->m_charmaps.size()) throw( Error(0, "in BitmapFontFace::getGlyph, i_charmapNo out of range") ); BitmapFontCharmap & charmap = m_shared->m_charmaps[i_charmapNo]; BitmapFontCharmap::const_iterator glyphItr = charmap.find(i_charCode); if (glyphItr == charmap.end()) { if (m_shared->m_replacementForMissingCharCode == 0) throw( Error(0, "in BitmapFontFace::getGlyph, no glyph in charmap for i_charCode") ); glyphItr = charmap.find(m_shared->m_replacementForMissingCharCode); if (glyphItr == charmap.end()) throw( Error(0, "in BitmapFontFace::getGlyph, no glyph in charmap for i_charCode or its replacement code") ); } return glyphItr->second; } const Bitmap & getGlyphBitmap(unsigned int i_charmapNo, unsigned int i_charCode) const { return m_shared->m_bitmaps[getGlyph(i_charmapNo, i_charCode).bitmapNo]; } const dan::math::Rect2I & getGlyphRect(unsigned int i_charmapNo, unsigned int i_charCode) const { return getGlyph(i_charmapNo, i_charCode).rect; } // + }}} dan::math::Vector2I charAdvanceMax() const { dan::math::Vector2I maxValue = 0; for (unsigned int charmapNo = 0; charmapNo < m_shared->m_charmaps.size(); ++charmapNo) { const BitmapFontCharmap & charmap = m_shared->m_charmaps[charmapNo]; for (BitmapFontCharmap::const_iterator glyphItr = charmap.begin(); glyphItr != charmap.end(); ++glyphItr) { if (glyphItr->second.advance[0] > maxValue[0]) maxValue[0] = glyphItr->second.advance[0]; if (glyphItr->second.advance[1] > maxValue[1]) maxValue[1] = glyphItr->second.advance[1]; } } return maxValue; } dan::math::Vector2I charRectSizeMax() const { dan::math::Vector2I maxValue = 0; for (unsigned int charmapNo = 0; charmapNo < m_shared->m_charmaps.size(); ++charmapNo) { const BitmapFontCharmap & charmap = m_shared->m_charmaps[charmapNo]; for (BitmapFontCharmap::const_iterator glyphItr = charmap.begin(); glyphItr != charmap.end(); ++glyphItr) { if (glyphItr->second.rect.width() > maxValue[0]) maxValue[0] = glyphItr->second.rect.width(); if (glyphItr->second.rect.height() > maxValue[1]) maxValue[1] = glyphItr->second.rect.height(); } } return maxValue; } }; }