28 #ifdef MYGUI_USE_FREETYPE
31 #include FT_TRUETYPE_TABLES_H
33 #include FT_WINFONTS_H
50 #ifndef MYGUI_USE_FREETYPE_BYTECODE_BUG_FIX
51 #define MYGUI_USE_FREETYPE_BYTECODE_BUG_FIX 1
54 #endif // MYGUI_USE_FREETYPE
63 void setMax(T& _var,
const T& _newValue)
69 std::pair<const Char, const uint8> charMaskData[] =
77 const std::map<const Char, const uint8> charMask(charMaskData, charMaskData +
sizeof charMaskData /
sizeof *charMaskData);
79 const uint8 charMaskBlack = (
const uint8)
'\x00';
80 const uint8 charMaskWhite = (
const uint8)
'\xFF';
89 static size_t getNumBytes();
98 struct PixelBase<false>
100 static size_t getNumBytes()
113 *_dest++ = _luminance;
114 *_dest++ = _luminance;
115 *_dest++ = _luminance;
121 struct PixelBase<true>
123 static size_t getNumBytes()
136 *_dest++ = _luminance;
141 template<
bool LAMode,
bool FromSource = false,
bool Antialias = false>
142 struct Pixel : PixelBase<LAMode>
152 template<
bool LAMode,
bool Antialias>
153 struct Pixel<LAMode, false, Antialias> : PixelBase<LAMode>
158 PixelBase<LAMode>::set(_dest, _luminance, _alpha);
162 template<
bool LAMode>
163 struct Pixel<LAMode, true, false> : PixelBase<LAMode>
168 PixelBase<LAMode>::set(_dest, _luminance, *_source++);
172 template<
bool LAMode>
173 struct Pixel<LAMode, true, true> : PixelBase<LAMode>
178 PixelBase<LAMode>::set(_dest, *_source, *_source);
185 const int ResourceTrueTypeFont::mGlyphSpacing = 1;
186 const float ResourceTrueTypeFont::mSelectedWidth = 1.0f;
187 const float ResourceTrueTypeFont::mCursorWidth = 2.0f;
196 mSubstituteCodePoint(FontCodeType::
NotDefined),
205 if (mTexture !=
nullptr)
219 if (node->
getName() ==
"Property")
223 if (key ==
"Source") mSource = value;
227 else if (key ==
"SpaceWidth")
230 MYGUI_LOG(Warning, _node->
findAttribute(
"type") <<
": Property '" << key <<
"' in font '" << _node->
findAttribute(
"name") <<
"' is deprecated; remove it to use automatic calculation.");
234 else if (key ==
"SubstituteCode") mSubstituteCodePoint =
utility::parseInt(value);
235 else if (key ==
"CursorWidth" || key ==
"Distance")
240 else if (node->
getName() ==
"Codes")
244 while (range.
next(
"Code"))
246 std::string range_value;
249 std::vector<std::string> parse_range =
utility::split(range_value);
250 if (!parse_range.empty())
254 addCodePointRange(first, last);
261 if (mCharMap.empty())
262 addCodePointRange(0, 0xFFFF);
266 while (range.
next(
"Code"))
268 std::string range_value;
271 std::vector<std::string> parse_range =
utility::split(range_value);
272 if (!parse_range.empty())
276 removeCodePointRange(first, last);
286 #ifdef MYGUI_USE_FREETYPE
290 CharMap::const_iterator charIter = mCharMap.find(_id);
292 if (charIter != mCharMap.end())
294 GlyphMap::iterator glyphIter = mGlyphMap.find(charIter->second);
296 if (glyphIter != mGlyphMap.end())
297 return &glyphIter->second;
300 return mSubstituteGlyphInfo;
310 #endif // MYGUI_USE_FREETYPE
319 return mDefaultHeight;
324 std::vector<std::pair<Char, Char> > result;
326 if (!mCharMap.empty())
328 CharMap::const_iterator iter = mCharMap.begin(), endIter = mCharMap.end();
331 Char rangeBegin = iter->first, rangeEnd = rangeBegin;
334 for (++iter; iter != endIter; ++iter)
336 if (iter->first == rangeEnd + 1)
344 result.push_back(std::make_pair(rangeBegin, rangeEnd));
347 rangeBegin = rangeEnd = iter->first;
352 result.push_back(std::make_pair(rangeBegin, rangeEnd));
360 return mSubstituteCodePoint;
363 void ResourceTrueTypeFont::addCodePoint(
Char _codePoint)
365 mCharMap.insert(CharMap::value_type(_codePoint, 0));
368 void ResourceTrueTypeFont::removeCodePoint(
Char _codePoint)
370 mCharMap.erase(_codePoint);
373 void ResourceTrueTypeFont::addCodePointRange(
Char _first,
Char _second)
375 CharMap::iterator positionHint = mCharMap.lower_bound(_first);
377 if (positionHint != mCharMap.begin())
380 for (
Char i = _first; i <= _second; ++i)
381 positionHint = mCharMap.insert(positionHint, CharMap::value_type(i, 0));
384 void ResourceTrueTypeFont::removeCodePointRange(
Char _first,
Char _second)
386 mCharMap.erase(mCharMap.lower_bound(_first), mCharMap.upper_bound(_second));
389 void ResourceTrueTypeFont::clearCodePoints()
394 void ResourceTrueTypeFont::initialise()
396 #ifndef MYGUI_USE_FREETYPE
398 MYGUI_LOG(Error,
"ResourceTrueTypeFont: TrueType font '" <<
getResourceName() <<
"' disabled. Define MYGUI_USE_FREETYE if you need TrueType fonts.");
400 #else // MYGUI_USE_FREETYPE
408 int init = (laMode ? 2 : 0) | (mAntialias ? 1 : 0);
413 ResourceTrueTypeFont::initialiseFreeType<false, false>();
416 ResourceTrueTypeFont::initialiseFreeType<false, true>();
419 ResourceTrueTypeFont::initialiseFreeType<true, false>();
422 ResourceTrueTypeFont::initialiseFreeType<true, true>();
426 #endif // MYGUI_USE_FREETYPE
429 #ifdef MYGUI_USE_FREETYPE
431 template<
bool LAMode,
bool Antialias>
432 void ResourceTrueTypeFont::initialiseFreeType()
438 FT_Library ftLibrary;
440 if (FT_Init_FreeType(&ftLibrary) != 0)
441 MYGUI_EXCEPT(
"ResourceTrueTypeFont: Could not init the FreeType library!");
443 uint8* fontBuffer =
nullptr;
445 FT_Face face = loadFace(ftLibrary, fontBuffer);
461 int fontAscent = face->size->metrics.ascender >> 6;
462 int fontDescent = -face->size->metrics.descender >> 6;
464 TT_OS2* os2 = (TT_OS2*)FT_Get_Sfnt_Table(face, ft_sfnt_os2);
468 setMax(fontAscent, os2->usWinAscent * face->size->metrics.y_ppem / face->units_per_EM);
469 setMax(fontDescent, os2->usWinDescent * face->size->metrics.y_ppem / face->units_per_EM);
471 setMax(fontAscent, os2->sTypoAscender * face->size->metrics.y_ppem / face->units_per_EM);
472 setMax(fontDescent, -os2->sTypoDescender * face->size->metrics.y_ppem / face->units_per_EM);
479 mDefaultHeight = fontAscent + fontDescent;
485 GlyphHeightMap glyphHeightMap;
493 for (CharMap::iterator iter = mCharMap.begin(); iter != mCharMap.end(); )
495 const Char& codePoint = iter->first;
496 FT_UInt glyphIndex = FT_Get_Char_Index(face, codePoint);
498 texWidth += createFaceGlyph(glyphIndex, codePoint, fontAscent, face, glyphHeightMap);
502 if (iter->second != 0)
505 mCharMap.erase(iter++);
508 #if MYGUI_USE_FREETYPE_BYTECODE_BUG_FIX
510 for (GlyphMap::iterator iter = mGlyphMap.begin(); iter != mGlyphMap.end(); ++iter)
512 if (FT_Load_Glyph(face, iter->first, FT_LOAD_DEFAULT) == 0)
514 GlyphInfo& info = iter->second;
515 GlyphInfo newInfo = createFaceGlyphInfo(0, fontAscent, face->glyph);
517 if (info.width != newInfo.width)
519 texWidth += (int)ceil(newInfo.width) - (int)ceil(info.width);
520 info.width = newInfo.width;
523 if (info.height != newInfo.height)
525 GlyphHeightMap::mapped_type oldHeightMap = glyphHeightMap[(FT_Pos)info.height];
526 GlyphHeightMap::mapped_type::iterator heightMapItem = oldHeightMap.find(iter->first);
527 glyphHeightMap[(FT_Pos)newInfo.height].insert(*heightMapItem);
528 oldHeightMap.erase(heightMapItem);
529 info.height = newInfo.height;
532 if (info.advance != newInfo.advance)
533 info.advance = newInfo.advance;
535 if (info.bearingX != newInfo.bearingX)
536 info.bearingX = newInfo.bearingX;
538 if (info.bearingY != newInfo.bearingY)
539 info.bearingY = newInfo.bearingY;
543 MYGUI_LOG(Warning,
"ResourceTrueTypeFont: Cannot load glyph " << iter->first <<
" for character " << iter->second.codePoint <<
" in font '" <<
getResourceName() <<
"'.");
547 #endif // MYGUI_USE_FREETYPE_BYTECODE_BUG_FIX
555 if (mSpaceWidth != 0.0f)
557 texWidth += (int)ceil(mSpaceWidth) - (int)ceil(spaceGlyphInfo->width);
558 spaceGlyphInfo->width = mSpaceWidth;
559 spaceGlyphInfo->advance = mSpaceWidth;
563 if (mTabWidth == 0.0f)
564 mTabWidth = 8.0f * spaceGlyphInfo->advance;
570 FT_UInt nextGlyphIndex = (FT_UInt)face->num_glyphs;
572 float height = (
float)mDefaultHeight;
574 texWidth += createGlyph(nextGlyphIndex++, GlyphInfo(
FontCodeType::Tab, 0.0f, 0.0f, mTabWidth, 0.0f, 0.0f), glyphHeightMap);
575 texWidth += createGlyph(nextGlyphIndex++, GlyphInfo(
FontCodeType::Selected, mSelectedWidth, height, 0.0f, 0.0f, 0.0f), glyphHeightMap);
576 texWidth += createGlyph(nextGlyphIndex++, GlyphInfo(
FontCodeType::SelectedBack, mSelectedWidth, height, 0.0f, 0.0f, 0.0f), glyphHeightMap);
577 texWidth += createGlyph(nextGlyphIndex++, GlyphInfo(
FontCodeType::Cursor, mCursorWidth, height, 0.0f, 0.0f, 0.0f), glyphHeightMap);
594 mSubstituteGlyphInfo = &mGlyphMap.find(mCharMap.find(mSubstituteCodePoint)->second)->second;
598 double averageGlyphHeight = 0.0;
600 for (GlyphHeightMap::const_iterator j = glyphHeightMap.begin(); j != glyphHeightMap.end(); ++j)
601 averageGlyphHeight += j->first * j->second.size();
603 averageGlyphHeight /= mGlyphMap.size();
616 while (texWidth > texHeight)
629 if (texHeight > texWidth * 2)
632 int texX = 0, texY = 0;
634 for (GlyphHeightMap::const_iterator j = glyphHeightMap.begin(); j != glyphHeightMap.end(); ++j)
636 for (GlyphHeightMap::mapped_type::const_iterator i = j->second.begin(); i != j->second.end(); ++i)
638 GlyphInfo& info = *i->second;
640 int glyphWidth = (int)ceil(info.width);
641 int glyphHeight = (int)ceil(info.height);
643 autoWrapGlyphPos(glyphWidth, texWidth, glyphHeight, texX, texY);
646 texX += mGlyphSpacing + glyphWidth;
652 while (texHeight > texWidth * 2);
664 if (texBuffer !=
nullptr)
667 for (
uint8* dest = texBuffer, * endDest = dest + texWidth * texHeight * Pixel<LAMode>::getNumBytes(); dest != endDest; )
668 Pixel<LAMode, false, false>::set(dest, charMaskWhite, charMaskBlack);
670 renderGlyphs<LAMode, Antialias>(glyphHeightMap, ftLibrary, face, texBuffer, texWidth, texHeight);
674 MYGUI_LOG(Info,
"ResourceTrueTypeFont: Font '" <<
getResourceName() <<
"' using texture size " << texWidth <<
" x " << texHeight <<
".");
675 MYGUI_LOG(Info,
"ResourceTrueTypeFont: Font '" <<
getResourceName() <<
"' using real height " << mDefaultHeight <<
" pixels.");
679 MYGUI_LOG(Error,
"ResourceTrueTypeFont: Error locking texture; pointer is nullptr.");
683 FT_Done_FreeType(ftLibrary);
685 delete [] fontBuffer;
688 FT_Face ResourceTrueTypeFont::loadFace(
const FT_Library& _ftLibrary,
uint8*& _fontBuffer)
690 FT_Face result =
nullptr;
695 if (datastream ==
nullptr)
698 size_t fontBufferSize = datastream->
size();
699 _fontBuffer =
new uint8[fontBufferSize];
700 datastream->read(_fontBuffer, fontBufferSize);
704 if (FT_New_Memory_Face(_ftLibrary, _fontBuffer, (FT_Long)fontBufferSize, -1, &result) != 0)
707 FT_Long numFaces = result->num_faces;
708 FT_Long faceIndex = 0;
711 if (FT_New_Memory_Face(_ftLibrary, _fontBuffer, (FT_Long)fontBufferSize, faceIndex, &result) != 0)
714 if (result->face_flags & FT_FACE_FLAG_SCALABLE)
718 FT_F26Dot6 ftSize = (FT_F26Dot6)(mSize * (1 << 6));
720 if (FT_Set_Char_Size(result, ftSize, 0, mResolution, mResolution) != 0)
724 if (mCharMap.empty())
725 addCodePointRange(0, 0xFFFF);
730 FT_WinFNT_HeaderRec fnt;
734 std::map<float, FT_Long> faceSizes;
738 if (FT_Get_WinFNT_Header(result, &fnt) != 0)
741 faceSizes.insert(std::make_pair((
float)fnt.nominal_point_size * fnt.vertical_resolution / mResolution, faceIndex));
743 FT_Done_Face(result);
745 if (++faceIndex < numFaces)
746 if (FT_New_Memory_Face(_ftLibrary, _fontBuffer, (FT_Long)fontBufferSize, faceIndex, &result) != 0)
749 while (faceIndex < numFaces);
751 std::map<float, FT_Long>::const_iterator iter = faceSizes.lower_bound(mSize);
753 faceIndex = (iter != faceSizes.end()) ? iter->second : faceSizes.rbegin()->second;
755 if (FT_New_Memory_Face(_ftLibrary, _fontBuffer, (FT_Long)fontBufferSize, faceIndex, &result) != 0)
760 if (FT_Select_Size(result, 0) != 0)
765 if (mCharMap.empty())
768 addCodePointRange(0x20, 0x7E);
772 if (fnt.charset == FT_WinFNT_ID_CP1252)
773 addCodePointRange(0xA0, 0xFF);
779 removeCodePointRange(0, 0x1F);
780 removeCodePointRange(0x100, std::numeric_limits<Char>::max());
784 if (fnt.charset == FT_WinFNT_ID_CP1252)
785 removeCodePointRange(0x7F, 0x9F);
787 removeCodePointRange(0x7F, 0xFF);
794 void ResourceTrueTypeFont::autoWrapGlyphPos(
int _glyphWidth,
int _texWidth,
int _lineHeight,
int& _texX,
int& _texY)
796 if (_glyphWidth > 0 && _texX + mGlyphSpacing + _glyphWidth > _texWidth)
799 _texY += mGlyphSpacing + _lineHeight;
803 GlyphInfo ResourceTrueTypeFont::createFaceGlyphInfo(
Char _codePoint,
int _fontAscent, FT_GlyphSlot _glyph)
805 float bearingX = _glyph->metrics.horiBearingX / 64.0f;
813 _glyph->metrics.width / 64.0f,
814 _glyph->metrics.height / 64.0f,
815 (_glyph->advance.x / 64.0f) - bearingX,
817 _fontAscent - (_glyph->metrics.horiBearingY / 64.0f) - mOffsetHeight);
820 int ResourceTrueTypeFont::createGlyph(FT_UInt _glyphIndex,
const GlyphInfo& _glyphInfo, GlyphHeightMap& _glyphHeightMap)
822 mCharMap[_glyphInfo.codePoint] = _glyphIndex;
823 GlyphInfo& info = mGlyphMap.insert(GlyphMap::value_type(_glyphIndex, _glyphInfo)).first->second;
824 _glyphHeightMap[(FT_Pos)_glyphInfo.height].insert(std::make_pair(_glyphIndex, &info));
826 int width = (int)ceil(_glyphInfo.width);
828 return (width > 0) ? mGlyphSpacing + width : 0;
831 int ResourceTrueTypeFont::createFaceGlyph(FT_UInt _glyphIndex,
Char _codePoint,
int _fontAscent,
const FT_Face& _face, GlyphHeightMap& _glyphHeightMap)
833 if (mGlyphMap.find(_glyphIndex) == mGlyphMap.end())
835 if (FT_Load_Glyph(_face, _glyphIndex, FT_LOAD_DEFAULT) == 0)
836 return createGlyph(_glyphIndex, createFaceGlyphInfo(_codePoint, _fontAscent, _face->glyph), _glyphHeightMap);
838 MYGUI_LOG(Warning,
"ResourceTrueTypeFont: Cannot load glyph " << _glyphIndex <<
" for character " << _codePoint <<
" in font '" <<
getResourceName() <<
"'.");
842 mCharMap[_codePoint] = _glyphIndex;
848 template<
bool LAMode,
bool Antialias>
849 void ResourceTrueTypeFont::renderGlyphs(
const GlyphHeightMap& _glyphHeightMap,
const FT_Library& _ftLibrary,
const FT_Face& _face,
uint8* _texBuffer,
int _texWidth,
int _texHeight)
852 FT_Bitmap_New(&ftBitmap);
854 int texX = 0, texY = 0;
856 for (GlyphHeightMap::const_iterator j = _glyphHeightMap.begin(); j != _glyphHeightMap.end(); ++j)
858 for (GlyphHeightMap::mapped_type::const_iterator i = j->second.begin(); i != j->second.end(); ++i)
860 GlyphInfo& info = *i->second;
862 switch (info.codePoint)
867 renderGlyph<LAMode, false, false>(info, charMaskWhite, charMaskBlack, charMask.find(info.codePoint)->second, j->first, _texBuffer, _texWidth, _texHeight, texX, texY);
872 glyphInfo->width = 0.0f;
873 glyphInfo->uvRect.right = glyphInfo->uvRect.left;
879 renderGlyph<LAMode, false, false>(info, charMaskWhite, charMaskBlack, charMask.find(info.codePoint)->second, j->first, _texBuffer, _texWidth, _texHeight, texX, texY);
883 if (FT_Load_Glyph(_face, i->first, FT_LOAD_RENDER) == 0)
885 if (_face->glyph->bitmap.buffer !=
nullptr)
887 uint8* glyphBuffer =
nullptr;
889 switch (_face->glyph->bitmap.pixel_mode)
891 case FT_PIXEL_MODE_GRAY:
892 glyphBuffer = _face->glyph->bitmap.buffer;
895 case FT_PIXEL_MODE_MONO:
897 if (FT_Bitmap_Convert(_ftLibrary, &_face->glyph->bitmap, &ftBitmap, 1) == 0)
900 for (
uint8* p = ftBitmap.buffer, * endP = p + ftBitmap.width * ftBitmap.rows; p != endP; ++p)
903 glyphBuffer = ftBitmap.buffer;
908 if (glyphBuffer !=
nullptr)
909 renderGlyph<LAMode, true, Antialias>(info, charMaskWhite, charMaskWhite, charMaskWhite, j->first, _texBuffer, _texWidth, _texHeight, texX, texY, glyphBuffer);
914 MYGUI_LOG(Warning,
"ResourceTrueTypeFont: Cannot render glyph " << i->first <<
" for character " << info.codePoint <<
" in font '" <<
getResourceName() <<
"'.");
921 FT_Bitmap_Done(_ftLibrary, &ftBitmap);
924 template<
bool LAMode,
bool UseBuffer,
bool Antialias>
925 void ResourceTrueTypeFont::renderGlyph(GlyphInfo& _info,
uint8 _luminance0,
uint8 _luminance1,
uint8 _alpha,
int _lineHeight,
uint8* _texBuffer,
int _texWidth,
int _texHeight,
int& _texX,
int& _texY,
uint8* _glyphBuffer)
927 int width = (int)ceil(_info.width);
928 int height = (int)ceil(_info.height);
930 autoWrapGlyphPos(width, _texWidth, _lineHeight, _texX, _texY);
932 uint8* dest = _texBuffer + (_texY * _texWidth + _texX) * Pixel<LAMode>::getNumBytes();
935 ptrdiff_t destNextRow = (_texWidth - width) * Pixel<LAMode>::getNumBytes();
937 for (
int j = height; j > 0; --j)
940 for (i = width; i > 1; i -= 2)
942 Pixel<LAMode, UseBuffer, Antialias>::set(dest, _luminance0, _alpha, _glyphBuffer);
943 Pixel<LAMode, UseBuffer, Antialias>::set(dest, _luminance1, _alpha, _glyphBuffer);
947 Pixel<LAMode, UseBuffer, Antialias>::set(dest, _luminance0, _alpha, _glyphBuffer);
953 _info.uvRect.left = (float)_texX / _texWidth;
954 _info.uvRect.top = (float)_texY / _texHeight;
955 _info.uvRect.right = (float)(_texX + _info.width) / _texWidth;
956 _info.uvRect.bottom = (float)(_texY + _info.height) / _texHeight;
959 _texX += mGlyphSpacing + width;
962 #endif // MYGUI_USE_FREETYPE
Char getSubstituteCodePoint() const
virtual void deserialization(xml::ElementPtr _node, Version _version)
virtual void createManual(int _width, int _height, TextureUsage _usage, PixelFormat _format)=0
int parseInt(const std::string &_value)
static RenderManager & getInstance()
virtual int getDefaultHeight()
unsigned int parseUInt(const std::string &_value)
bool findAttribute(const std::string &_name, std::string &_value)
virtual void * lock(TextureUsage _access)=0
const std::string & getResourceName() const
#define MYGUI_LOG(level, text)
virtual ITexture * getTextureFont()
virtual bool isFormatSupported(PixelFormat _format, TextureUsage _usage)
std::vector< std::string > split(const std::string &_source, const std::string &_delims="\t\n ")
#define MYGUI_EXCEPT(dest)
virtual void deserialization(xml::ElementPtr _node, Version _version)
static __inline Type firstPO2From(Type _value)
std::string toString(T p)
virtual IDataStream * getData(const std::string &_name)=0
float parseFloat(const std::string &_value)
bool parseBool(const std::string &_value)
virtual ~ResourceTrueTypeFont()
ElementEnumerator getElementEnumerator()
virtual GlyphInfo * getGlyphInfo(Char _id)
const std::string & getName() const
virtual ITexture * createTexture(const std::string &_name)=0
std::vector< std::pair< Char, Char > > getCodePointRanges() const
virtual void destroyTexture(ITexture *_texture)=0