MyGUI  3.4.1
MyGUI_ResourceTrueTypeFont.cpp
Go to the documentation of this file.
1 /*
2  * This source file is part of MyGUI. For the latest info, see http://mygui.info/
3  * Distributed under the MIT License
4  * (See accompanying file COPYING.MIT or copy at http://opensource.org/licenses/MIT)
5  */
6 
7 #include "MyGUI_Precompiled.h"
9 #include "MyGUI_DataManager.h"
10 #include "MyGUI_DataStreamHolder.h"
11 #include "MyGUI_RenderManager.h"
12 #include "MyGUI_Bitwise.h"
13 
14 #ifdef MYGUI_USE_FREETYPE
15 
16 # include FT_GLYPH_H
17 # include FT_TRUETYPE_TABLES_H
18 # include FT_BITMAP_H
19 # include FT_WINFONTS_H
20 
21 #ifdef MYGUI_MSDF_FONTS
22 #include "msdfgen/msdfgen.h"
23 #include "msdfgen/msdfgen-ext.h"
24 #endif
25 
26 #endif // MYGUI_USE_FREETYPE
27 
28 namespace MyGUI
29 {
30 
31 #ifndef MYGUI_USE_FREETYPE
33  {
34  }
35 
37  {
38  }
39 
41  {
42  Base::deserialization(_node, _version);
43  MYGUI_LOG(Error, "ResourceTrueTypeFont: TrueType font '" << getResourceName() << "' disabled. Define MYGUI_USE_FREETYE if you need TrueType fonts.");
44  }
45 
47  {
48  return nullptr;
49  }
50 
52  {
53  return nullptr;
54  }
55 
57  {
58  return 0;
59  }
60 
62  {
63  }
64 
65  std::vector<std::pair<Char, Char> > ResourceTrueTypeFont::getCodePointRanges() const
66  {
67  return std::vector<std::pair<Char, Char> >();
68  }
69 
71  {
72  return Char();
73  }
74 
76  {
77  }
78 
79  void ResourceTrueTypeFont::setSource(const std::string& _value)
80  {
81  }
82 
83  void ResourceTrueTypeFont::setShader(const std::string& _value)
84  {
85  }
86 
87  void ResourceTrueTypeFont::setSize(float _value)
88  {
89  }
90 
91  void ResourceTrueTypeFont::setResolution(unsigned int _value)
92  {
93  }
94 
95  void ResourceTrueTypeFont::setHinting(const std::string& _value)
96  {
97  }
98 
100  {
101  }
102 
104  {
105  }
106 
108  {
109  }
110 
112  {
113  }
114 
116  {
117  }
118 
120  {
121  }
122 
124  {
125  }
126 
128  {
129  }
130 
132  {
133  }
134 
135 #else // MYGUI_USE_FREETYPE
136  namespace
137  {
138 
139  template<typename T>
140  void setMax(T& _var, const T& _newValue)
141  {
142  if (_var < _newValue)
143  _var = _newValue;
144  }
145 
146  std::pair<const Char, const uint8> charMaskData[] =
147  {
148  std::make_pair(FontCodeType::Selected, (const uint8)'\x88'),
149  std::make_pair(FontCodeType::SelectedBack, (const uint8)'\x60'),
150  std::make_pair(FontCodeType::Cursor, (const uint8)'\xFF'),
151  std::make_pair(FontCodeType::Tab, (const uint8)'\x00')
152  };
153 
154  const std::map<const Char, const uint8> charMask(charMaskData, charMaskData + sizeof charMaskData / sizeof(*charMaskData));
155 
156  const uint8 charMaskBlack = (const uint8)'\x00';
157  const uint8 charMaskWhite = (const uint8)'\xFF';
158 
159  template<bool LAMode>
160  struct PixelBase
161  {
162  // Returns PixelFormat::R8G8B8A8 when LAMode is false, or PixelFormat::L8A8 when LAMode is true.
163  static PixelFormat::Enum getFormat();
164 
165  // Returns 4 when LAMode is false, or 2 when LAMode is true.
166  static size_t getNumBytes();
167 
168  protected:
169  // Sets a pixel in _dest as 4 or 2 bytes: L8L8L8A8 if LAMode is false, or L8A8 if LAMode is true.
170  // Automatically advances _dest just past the pixel written.
171  static void set(uint8*& _dest, uint8 _luminance, uint8 _alpha);
172  };
173 
174  template<>
175  struct PixelBase<false>
176  {
177  static size_t getNumBytes()
178  {
179  return 4;
180  }
181 
182  static PixelFormat::Enum getFormat()
183  {
184  return PixelFormat::R8G8B8A8;
185  }
186 
187  protected:
188  static void set(uint8*& _dest, uint8 _luminance, uint8 _alpha)
189  {
190  *_dest++ = _luminance;
191  *_dest++ = _luminance;
192  *_dest++ = _luminance;
193  *_dest++ = _alpha;
194  }
195  };
196 
197  template<>
198  struct PixelBase<true>
199  {
200  static size_t getNumBytes()
201  {
202  return 2;
203  }
204 
205  static PixelFormat::Enum getFormat()
206  {
207  return PixelFormat::L8A8;
208  }
209 
210  protected:
211  static void set(uint8*& _dest, uint8 _luminance, uint8 _alpha)
212  {
213  *_dest++ = _luminance;
214  *_dest++ = _alpha;
215  }
216  };
217 
218  template<bool LAMode, bool FromSource = false, bool Antialias = false>
219  struct Pixel : PixelBase<LAMode>
220  {
221  // Sets a pixel in _dest as 4 or 2 bytes: L8L8L8A8 if LAMode is false, or L8A8 if LAMode is true.
222  // Sets luminance from _source if both FromSource and Antialias are true; otherwise, uses the specified value.
223  // Sets alpha from _source if FromSource is true; otherwise, uses the specified value.
224  // Automatically advances _source just past the pixel read if FromSource is true.
225  // Automatically advances _dest just past the pixel written.
226  static void set(uint8*& _dest, uint8 _luminance, uint8 _alpha, uint8*& _source);
227  };
228 
229  template<bool LAMode, bool Antialias>
230  struct Pixel<LAMode, false, Antialias> : PixelBase<LAMode>
231  {
232  // Sets the destination pixel using the specified luminance and alpha. Source is ignored, since FromSource is false.
233  static void set(uint8*& _dest, uint8 _luminance, uint8 _alpha, uint8* /*_source*/ = nullptr)
234  {
235  PixelBase<LAMode>::set(_dest, _luminance, _alpha);
236  }
237  };
238 
239  template<bool LAMode>
240  struct Pixel<LAMode, true, false> : PixelBase<LAMode>
241  {
242  // Sets the destination pixel using the specified _luminance and using the alpha from the specified source.
243  static void set(uint8*& _dest, uint8 _luminance, uint8 /*_alpha*/, uint8*& _source)
244  {
245  PixelBase<LAMode>::set(_dest, _luminance, *_source++);
246  }
247  };
248 
249  template<bool LAMode>
250  struct Pixel<LAMode, true, true> : PixelBase<LAMode>
251  {
252  // Sets the destination pixel using both the luminance and alpha from the specified source, since Antialias is true.
253  static void set(uint8*& _dest, uint8 /*_luminance*/, uint8 /*_alpha*/, uint8*& _source)
254  {
255  PixelBase<LAMode>::set(_dest, *_source, *_source);
256  ++_source;
257  }
258  };
259 
260  }
261 
262  const int ResourceTrueTypeFont::mDefaultGlyphSpacing = 1;
263  const float ResourceTrueTypeFont::mDefaultTabWidth = 8.0f;
264  const float ResourceTrueTypeFont::mSelectedWidth = 1.0f;
265  const float ResourceTrueTypeFont::mCursorWidth = 2.0f;
266 
268  mSize(0),
269  mResolution(96),
270  mHinting(HintingUseNative),
271  mAntialias(false),
272  mSpaceWidth(0.0f),
273  mGlyphSpacing(-1),
274  mTabWidth(0.0f),
275  mOffsetHeight(0),
276  mSubstituteCodePoint(static_cast<Char>(FontCodeType::NotDefined)),
277  mMsdfMode(false),
278  mMsdfRange(2),
279  mDefaultHeight(0),
280  mSubstituteGlyphInfo(nullptr),
281  mTexture(nullptr)
282  {
283  }
284 
286  {
287  if (mTexture != nullptr)
288  {
290  mTexture = nullptr;
291  }
292  }
293 
294  void ResourceTrueTypeFont::deserialization(xml::ElementPtr _node, Version _version)
295  {
296  Base::deserialization(_node, _version);
297 
298  xml::ElementEnumerator node = _node->getElementEnumerator();
299  while (node.next())
300  {
301  if (node->getName() == "Property")
302  {
303  const std::string& key = node->findAttribute("key");
304  const std::string& value = node->findAttribute("value");
305  if (key == "Source")
306  setSource(value);
307  else if (key == "Shader")
308  setShader(value);
309  else if (key == "Size")
311  else if (key == "Resolution")
313  else if (key == "Antialias")
315  else if (key == "TabWidth")
317  else if (key == "OffsetHeight")
319  else if (key == "SubstituteCode")
321  else if (key == "Distance")
323  else if (key == "Hinting")
324  setHinting(value);
325  else if (key == "SpaceWidth")
326  {
327  mSpaceWidth = utility::parseFloat(value);
328  MYGUI_LOG(Warning, _node->findAttribute("type") << ": Property '" << key << "' in font '" << _node->findAttribute("name") << "' is deprecated; remove it to use automatic calculation.");
329  }
330  else if (key == "CursorWidth")
331  {
332  MYGUI_LOG(Warning, _node->findAttribute("type") << ": Property '" << key << "' in font '" << _node->findAttribute("name") << "' is deprecated; value ignored.");
333  }
334  else if (key == "MsdfMode")
335  {
337  }
338  else if (key == "MsdfRange")
339  {
341  }
342  }
343  else if (node->getName() == "Codes")
344  {
345  // Range of inclusions.
346  xml::ElementEnumerator range = node->getElementEnumerator();
347  while (range.next("Code"))
348  {
349  std::string range_value;
350  if (range->findAttribute("range", range_value))
351  {
352  std::vector<std::string> parse_range = utility::split(range_value);
353  if (!parse_range.empty())
354  {
355  Char first = utility::parseUInt(parse_range[0]);
356  Char last = parse_range.size() > 1 ? utility::parseUInt(parse_range[1]) : first;
357  addCodePointRange(first, last);
358  }
359  }
360  }
361 
362  // If no code points have been included, include the Unicode Basic Multilingual Plane by default before processing
363  // any exclusions.
364  if (mCharMap.empty())
365  addCodePointRange(0, 0xFFFF);
366 
367  // Range of exclusions.
368  range = node->getElementEnumerator();
369  while (range.next("Code"))
370  {
371  std::string range_value;
372  if (range->findAttribute("hide", range_value))
373  {
374  std::vector<std::string> parse_range = utility::split(range_value);
375  if (!parse_range.empty())
376  {
377  Char first = utility::parseUInt(parse_range[0]);
378  Char last = parse_range.size() > 1 ? utility::parseUInt(parse_range[1]) : first;
379  removeCodePointRange(first, last);
380  }
381  }
382  }
383  }
384  }
385 
386  initialise();
387  }
388 
389  const GlyphInfo* ResourceTrueTypeFont::getGlyphInfo(Char _id) const
390  {
391  GlyphMap::const_iterator glyphIter = mGlyphMap.find(_id);
392 
393  if (glyphIter != mGlyphMap.end())
394  {
395  return &glyphIter->second;
396  }
397 
398  return mSubstituteGlyphInfo;
399  }
400 
401  ITexture* ResourceTrueTypeFont::getTextureFont() const
402  {
403  return mTexture;
404  }
405 
407  {
408  return mDefaultHeight;
409  }
410 
411  void ResourceTrueTypeFont::textureInvalidate(ITexture* _texture)
412  {
413  mGlyphMap.clear();
414  initialise();
415  }
416 
417  std::vector<std::pair<Char, Char> > ResourceTrueTypeFont::getCodePointRanges() const
418  {
419  std::vector<std::pair<Char, Char> > result;
420 
421  if (!mCharMap.empty())
422  {
423  CharMap::const_iterator iter = mCharMap.begin(), endIter = mCharMap.end();
424 
425  // Start the first range with the first code point in the map.
426  Char rangeBegin = iter->first, rangeEnd = rangeBegin;
427 
428  // Loop over the rest of the map and find the contiguous ranges.
429  for (++iter; iter != endIter; ++iter)
430  {
431  if (iter->first == rangeEnd + 1)
432  {
433  // Extend the current range.
434  ++rangeEnd;
435  }
436  else
437  {
438  // Found the start of a new range. First, save the current range.
439  result.push_back(std::make_pair(rangeBegin, rangeEnd));
440 
441  // Then start the new range.
442  rangeBegin = rangeEnd = iter->first;
443  }
444  }
445 
446  // Save the final range.
447  result.push_back(std::make_pair(rangeBegin, rangeEnd));
448  }
449 
450  return result;
451  }
452 
454  {
455  return mSubstituteCodePoint;
456  }
457 
458  void ResourceTrueTypeFont::addCodePoint(Char _codePoint)
459  {
460  mCharMap.insert(CharMap::value_type(_codePoint, 0));
461  }
462 
463  void ResourceTrueTypeFont::removeCodePoint(Char _codePoint)
464  {
465  mCharMap.erase(_codePoint);
466  }
467 
469  {
470  CharMap::iterator positionHint = mCharMap.lower_bound(_first);
471 
472  if (positionHint != mCharMap.begin())
473  --positionHint;
474 
475  for (Char i = _first; i <= _second; ++i)
476  positionHint = mCharMap.insert(positionHint, CharMap::value_type(i, 0));
477  }
478 
480  {
481  mCharMap.erase(mCharMap.lower_bound(_first), mCharMap.upper_bound(_second));
482  }
483 
484  void ResourceTrueTypeFont::clearCodePoints()
485  {
486  mCharMap.clear();
487  }
488 
490  {
491  if (mGlyphSpacing == -1)
492  mGlyphSpacing = mDefaultGlyphSpacing;
493 
494  // If L8A8 (2 bytes per pixel) is supported, use it; otherwise, use R8G8B8A8 (4 bytes per pixel) as L8L8L8A8.
496  if (mMsdfMode)
497  laMode = false;
498 
499  // Select and call an appropriate initialisation method. By making this decision up front, we avoid having to branch on
500  // these variables many thousands of times inside tight nested loops later. From this point on, the various function
501  // templates ensure that all of the necessary branching is done purely at compile time for all combinations.
502  int init = (laMode ? 2 : 0) | (mAntialias ? 1 : 0);
503 
504  switch (init)
505  {
506  case 0:
507  ResourceTrueTypeFont::initialiseFreeType<false, false>();
508  break;
509  case 1:
510  ResourceTrueTypeFont::initialiseFreeType<false, true>();
511  break;
512  case 2:
513  ResourceTrueTypeFont::initialiseFreeType<true, false>();
514  break;
515  case 3:
516  ResourceTrueTypeFont::initialiseFreeType<true, true>();
517  break;
518  }
519  }
520 
521  template<bool LAMode, bool Antialias>
522  void ResourceTrueTypeFont::initialiseFreeType()
523  {
524  //-------------------------------------------------------------------//
525  // Initialise FreeType and load the font.
526  //-------------------------------------------------------------------//
527 
528  FT_Library ftLibrary;
529 
530  if (FT_Init_FreeType(&ftLibrary) != 0)
531  MYGUI_EXCEPT("ResourceTrueTypeFont: Could not init the FreeType library!");
532 
533  uint8* fontBuffer = nullptr;
534 
535  FT_Face ftFace = loadFace(ftLibrary, fontBuffer);
536 
537  if (ftFace == nullptr)
538  {
539  MYGUI_LOG(Error, "ResourceTrueTypeFont: Could not load the font '" << getResourceName() << "'!");
540  FT_Done_FreeType(ftLibrary);
541  return;
542  }
543 
544 #ifdef MYGUI_MSDF_FONTS
545  msdfgen::FontHandle* msdfFont = nullptr;
546 
547  if (mMsdfMode)
548  {
549  msdfFont = msdfgen::adoptFreetypeFont(ftFace);
550  }
551 #endif
552 
553  //-------------------------------------------------------------------//
554  // Calculate the font metrics.
555  //-------------------------------------------------------------------//
556 
557  // The font's overall ascent and descent are defined in three different places in a TrueType font, and with different
558  // values in each place. The most reliable source for these metrics is usually the "usWinAscent" and "usWinDescent" pair of
559  // values in the OS/2 header; however, some fonts contain inaccurate data there. To be safe, we use the highest of the set
560  // of values contained in the face metrics and the two sets of values contained in the OS/2 header.
561  int fontAscent = ftFace->size->metrics.ascender >> 6;
562  int fontDescent = -ftFace->size->metrics.descender >> 6;
563 
564  TT_OS2* os2 = (TT_OS2*)FT_Get_Sfnt_Table(ftFace, ft_sfnt_os2);
565 
566  if (os2 != nullptr)
567  {
568  setMax(fontAscent, os2->usWinAscent * ftFace->size->metrics.y_ppem / ftFace->units_per_EM);
569  setMax(fontDescent, os2->usWinDescent * ftFace->size->metrics.y_ppem / ftFace->units_per_EM);
570 
571  setMax(fontAscent, os2->sTypoAscender * ftFace->size->metrics.y_ppem / ftFace->units_per_EM);
572  setMax(fontDescent, -os2->sTypoDescender * ftFace->size->metrics.y_ppem / ftFace->units_per_EM);
573  }
574 
575  // The nominal font height is calculated as the sum of its ascent and descent as specified by the font designer. Previously
576  // it was defined by MyGUI in terms of the maximum ascent and descent of the glyphs currently in use, but this caused the
577  // font's line spacing to change whenever glyphs were added to or removed from the font definition. Doing it this way
578  // instead prevents a lot of layout problems, and it is also more typographically correct and more aesthetically pleasing.
579  mDefaultHeight = fontAscent + fontDescent;
580 
581  // Set the load flags based on the specified type of hinting.
582  FT_Int32 ftLoadFlags = FT_LOAD_DEFAULT;
583 
584  switch (mHinting)
585  {
586  case HintingForceAuto:
587  ftLoadFlags = FT_LOAD_FORCE_AUTOHINT;
588  break;
589  case HintingDisableAuto:
590  ftLoadFlags = FT_LOAD_NO_AUTOHINT;
591  break;
592  case HintingDisableAll:
593  // When hinting is completely disabled, glyphs must always be rendered -- even during layout calculations -- due to
594  // discrepancies between the glyph metrics and the actual rendered bitmap metrics.
595  ftLoadFlags = FT_LOAD_NO_HINTING | FT_LOAD_RENDER;
596  break;
597  case HintingUseNative:
598  ftLoadFlags = FT_LOAD_DEFAULT;
599  break;
600  }
601 
602  //-------------------------------------------------------------------//
603  // Create the glyphs and calculate their metrics.
604  //-------------------------------------------------------------------//
605 
606  GlyphHeightMap glyphHeightMap;
607  int texWidth = 0;
608 
609  // Before creating the glyphs, add the "Space" code point to force that glyph to be created. For historical reasons, MyGUI
610  // users are accustomed to omitting this code point in their font definitions.
611  addCodePoint(FontCodeType::Space);
612 
613  // Create the standard glyphs.
614  for (CharMap::iterator iter = mCharMap.begin(); iter != mCharMap.end(); )
615  {
616  const Char& codePoint = iter->first;
617  FT_UInt glyphIndex = FT_Get_Char_Index(ftFace, codePoint);
618 
619  if (!mMsdfMode)
620  texWidth += createFaceGlyph(glyphIndex, codePoint, fontAscent, ftFace, ftLoadFlags, glyphHeightMap);
621 #ifdef MYGUI_MSDF_FONTS
622  else
623  texWidth += createMsdfFaceGlyph(codePoint, fontAscent, msdfFont, glyphHeightMap);
624 #endif
625 
626  // If the newly created glyph is the "Not Defined" glyph, it means that the code point is not supported by the font.
627  // Remove it from the character map so that we can provide our own substitute instead of letting FreeType do it.
628  if (iter->second != 0)
629  ++iter;
630  else
631  mCharMap.erase(iter++);
632  }
633 
634  // Do some special handling for the "Space" and "Tab" glyphs.
635  GlyphMap::iterator spaceGlyphIter = mGlyphMap.find(FontCodeType::Space);
636 
637  if (spaceGlyphIter != mGlyphMap.end())
638  {
639  // Adjust the width of the "Space" glyph if it has been customized.
640  if (mSpaceWidth != 0.0f)
641  {
642  texWidth += (int)std::ceil(mSpaceWidth) - (int)std::ceil(spaceGlyphIter->second.width);
643  spaceGlyphIter->second.width = mSpaceWidth;
644  spaceGlyphIter->second.advance = mSpaceWidth;
645  }
646 
647  // If the width of the "Tab" glyph hasn't been customized, make it eight spaces wide.
648  if (mTabWidth == 0.0f)
649  mTabWidth = mDefaultTabWidth * spaceGlyphIter->second.advance;
650  }
651 
652  // Create the special glyphs. They must be created after the standard glyphs so that they take precedence in case of a
653  // collision. To make sure that the indices of the special glyphs don't collide with any glyph indices in the font, we must
654  // use glyph indices higher than the highest glyph index in the font.
655  FT_UInt nextGlyphIndex = (FT_UInt)ftFace->num_glyphs;
656 
657  float height = (float)mDefaultHeight;
658 
659  texWidth += createGlyph(nextGlyphIndex++, GlyphInfo(static_cast<Char>(FontCodeType::Tab), 0.0f, 0.0f, mTabWidth, 0.0f, 0.0f), glyphHeightMap);
660  texWidth += createGlyph(nextGlyphIndex++, GlyphInfo(static_cast<Char>(FontCodeType::Selected), mSelectedWidth, height, 0.0f, 0.0f, 0.0f), glyphHeightMap);
661  texWidth += createGlyph(nextGlyphIndex++, GlyphInfo(static_cast<Char>(FontCodeType::SelectedBack), mSelectedWidth, height, 0.0f, 0.0f, 0.0f), glyphHeightMap);
662  texWidth += createGlyph(nextGlyphIndex++, GlyphInfo(static_cast<Char>(FontCodeType::Cursor), mCursorWidth, height, 0.0f, 0.0f, 0.0f), glyphHeightMap);
663 
664  // If a substitute code point has been specified, check to make sure that it exists in the character map. If it doesn't,
665  // revert to the default "Not Defined" code point. This is not a real code point but rather an invalid Unicode value that
666  // is guaranteed to cause the "Not Defined" special glyph to be created.
667  if (mSubstituteCodePoint != FontCodeType::NotDefined && mCharMap.find(mSubstituteCodePoint) == mCharMap.end())
668  mSubstituteCodePoint = static_cast<Char>(FontCodeType::NotDefined);
669 
670  // Create the "Not Defined" code point (and its corresponding glyph) if it's in use as the substitute code point.
671  if (mSubstituteCodePoint == FontCodeType::NotDefined)
672  {
673  if (!mMsdfMode)
674  texWidth += createFaceGlyph(0, static_cast<Char>(FontCodeType::NotDefined), fontAscent, ftFace, ftLoadFlags, glyphHeightMap);
675 #ifdef MYGUI_MSDF_FONTS
676  else
677  texWidth += createMsdfFaceGlyph(static_cast<Char>(FontCodeType::NotDefined), fontAscent, msdfFont, glyphHeightMap);
678 #endif
679  }
680 
681  // Cache a pointer to the substitute glyph info for fast lookup.
682  mSubstituteGlyphInfo = &mGlyphMap.find(mSubstituteCodePoint)->second;
683 
684  // Calculate the average height of all of the glyphs that are in use. This value will be used for estimating how large the
685  // texture needs to be.
686  double averageGlyphHeight = 0.0;
687 
688  for (GlyphHeightMap::const_iterator j = glyphHeightMap.begin(); j != glyphHeightMap.end(); ++j)
689  averageGlyphHeight += j->first * j->second.size();
690 
691  averageGlyphHeight /= mGlyphMap.size();
692 
693  //-------------------------------------------------------------------//
694  // Calculate the final texture size.
695  //-------------------------------------------------------------------//
696 
697  // Round the current texture width and height up to the nearest powers of two.
698  texWidth = Bitwise::firstPO2From(texWidth);
699  int texHeight = Bitwise::firstPO2From((int)ceil(averageGlyphHeight) + mGlyphSpacing);
700 
701  // At this point, the texture is only one glyph high and is probably very wide. For efficiency reasons, we need to make the
702  // texture as square as possible. If the texture cannot be made perfectly square, make it taller than it is wide, because
703  // the height may decrease in the final layout due to height packing.
704  while (texWidth > texHeight)
705  {
706  texWidth /= 2;
707  texHeight *= 2;
708  }
709 
710  // Calculate the final layout of all of the glyphs in the texture, packing them tightly by first arranging them by height.
711  // We assume that the texture width is fixed but that the texture height can be adjusted up or down depending on how much
712  // space is actually needed.
713  // In most cases, the final texture will end up square or almost square. In some rare cases, however, we can end up with a
714  // texture that's more than twice as high as it is wide; when this happens, we double the width and try again.
715  do
716  {
717  if (texHeight > texWidth * 2)
718  texWidth *= 2;
719 
720  int texX = mGlyphSpacing;
721  int texY = mGlyphSpacing;
722 
723  for (GlyphHeightMap::const_iterator j = glyphHeightMap.begin(); j != glyphHeightMap.end(); ++j)
724  {
725  for (GlyphHeightMap::mapped_type::const_iterator i = j->second.begin(); i != j->second.end(); ++i)
726  {
727  GlyphInfo& info = *i->second;
728 
729  int glyphWidth = (int)std::ceil(info.width);
730  int glyphHeight = (int)std::ceil(info.height);
731 
732  autoWrapGlyphPos(glyphWidth, texWidth, glyphHeight, texX, texY);
733 
734  if (glyphWidth > 0)
735  texX += mGlyphSpacing + glyphWidth;
736  }
737  }
738 
739  texHeight = Bitwise::firstPO2From(texY + glyphHeightMap.rbegin()->first);
740  }
741  while (texHeight > texWidth * 2);
742 
743  //-------------------------------------------------------------------//
744  // Create the texture and render the glyphs onto it.
745  //-------------------------------------------------------------------//
746 
747  if (mTexture)
748  {
750  mTexture = nullptr;
751  }
752 
753  mTexture = RenderManager::getInstance().createTexture(MyGUI::utility::toString((size_t)this, "_TrueTypeFont"));
754 
755  mTexture->createManual(texWidth, texHeight, TextureUsage::Static | TextureUsage::Write, Pixel<LAMode>::getFormat());
756  mTexture->setInvalidateListener(this);
757 
758  if (!mShader.empty())
759  mTexture->setShader(mShader);
760 
761  uint8* texBuffer = static_cast<uint8*>(mTexture->lock(TextureUsage::Write));
762 
763  if (texBuffer != nullptr)
764  {
765  // Make the texture background transparent white (or black for msdf mode).
766  for (uint8* dest = texBuffer, * endDest = dest + texWidth * texHeight * Pixel<LAMode>::getNumBytes(); dest != endDest; )
767  Pixel<LAMode, false, false>::set(dest, mMsdfMode ? charMaskBlack : charMaskWhite, charMaskBlack);
768 
769  if (!mMsdfMode)
770  renderGlyphs<LAMode, Antialias>(glyphHeightMap, ftLibrary, ftFace, ftLoadFlags, texBuffer, texWidth, texHeight);
771 #ifdef MYGUI_MSDF_FONTS
772  else
773  renderMsdfGlyphs(glyphHeightMap, msdfFont, texBuffer, texWidth, texHeight);
774 #endif
775 
776  mTexture->unlock();
777 
778  MYGUI_LOG(Info, "ResourceTrueTypeFont: Font '" << getResourceName() << "' using texture size " << texWidth << " x " << texHeight << ".");
779  MYGUI_LOG(Info, "ResourceTrueTypeFont: Font '" << getResourceName() << "' using real height " << mDefaultHeight << " pixels.");
780  }
781  else
782  {
783  MYGUI_LOG(Error, "ResourceTrueTypeFont: Error locking texture; pointer is nullptr.");
784  }
785 
786 #ifdef MYGUI_MSDF_FONTS
787  if (mMsdfMode)
788  {
789  msdfgen::destroyFont(msdfFont);
790  }
791 #endif
792 
793  FT_Done_Face(ftFace);
794  FT_Done_FreeType(ftLibrary);
795 
796  delete [] fontBuffer;
797  }
798 
799  FT_Face ResourceTrueTypeFont::loadFace(const FT_Library& _ftLibrary, uint8*& _fontBuffer)
800  {
801  FT_Face result = nullptr;
802 
803  // Load the font file.
804  IDataStream* datastream = DataManager::getInstance().getData(mSource);
805 
806  if (datastream == nullptr)
807  return result;
808 
809  size_t fontBufferSize = datastream->size();
810  _fontBuffer = new uint8[fontBufferSize];
811  datastream->read(_fontBuffer, fontBufferSize);
812 
813  DataManager::getInstance().freeData(datastream);
814  datastream = nullptr;
815 
816  // Determine how many faces the font contains.
817  if (FT_New_Memory_Face(_ftLibrary, _fontBuffer, (FT_Long)fontBufferSize, -1, &result) != 0)
818  MYGUI_EXCEPT("ResourceTrueTypeFont: Could not load the font '" << getResourceName() << "'!");
819 
820  FT_Long numFaces = result->num_faces;
821  FT_Long faceIndex = 0;
822 
823  // Load the first face.
824  if (FT_New_Memory_Face(_ftLibrary, _fontBuffer, (FT_Long)fontBufferSize, faceIndex, &result) != 0)
825  MYGUI_EXCEPT("ResourceTrueTypeFont: Could not load the font '" << getResourceName() << "'!");
826 
827  if (result->face_flags & FT_FACE_FLAG_SCALABLE)
828  {
829  // The font is scalable, so set the font size by first converting the requested size to FreeType's 26.6 fixed-point
830  // format.
831  FT_F26Dot6 ftSize = (FT_F26Dot6)(mSize * (1 << 6));
832 
833  if (FT_Set_Char_Size(result, ftSize, 0, mResolution, mResolution) != 0)
834  MYGUI_EXCEPT("ResourceTrueTypeFont: Could not set the font size for '" << getResourceName() << "'!");
835 
836  // If no code points have been specified, use the Unicode Basic Multilingual Plane by default.
837  if (mCharMap.empty())
838  addCodePointRange(0, 0xFFFF);
839  }
840  else
841  {
842  // The font isn't scalable, so try to load it as a Windows FNT/FON file.
843  FT_WinFNT_HeaderRec fnt;
844 
845  // Enumerate all of the faces in the font and select the smallest one that's at least as large as the requested size
846  // (after adjusting for resolution). If none of the faces are large enough, use the largest one.
847  std::map<float, FT_Long> faceSizes;
848 
849  do
850  {
851  if (FT_Get_WinFNT_Header(result, &fnt) != 0)
852  MYGUI_EXCEPT("ResourceTrueTypeFont: Could not load the font '" << getResourceName() << "'!");
853 
854  faceSizes.insert(std::make_pair((float)fnt.nominal_point_size * fnt.vertical_resolution / mResolution, faceIndex));
855 
856  FT_Done_Face(result);
857 
858  if (++faceIndex < numFaces)
859  if (FT_New_Memory_Face(_ftLibrary, _fontBuffer, (FT_Long)fontBufferSize, faceIndex, &result) != 0)
860  MYGUI_EXCEPT("ResourceTrueTypeFont: Could not load the font '" << getResourceName() << "'!");
861  }
862  while (faceIndex < numFaces);
863 
864  std::map<float, FT_Long>::const_iterator iter = faceSizes.lower_bound(mSize);
865 
866  faceIndex = (iter != faceSizes.end()) ? iter->second : faceSizes.rbegin()->second;
867 
868  if (FT_New_Memory_Face(_ftLibrary, _fontBuffer, (FT_Long)fontBufferSize, faceIndex, &result) != 0)
869  MYGUI_EXCEPT("ResourceTrueTypeFont: Could not load the font '" << getResourceName() << "'!");
870 
871  // Select the first bitmap strike available in the selected face. This needs to be done explicitly even though Windows
872  // FNT/FON files contain only one bitmap strike per face.
873  if (FT_Select_Size(result, 0) != 0)
874  MYGUI_EXCEPT("ResourceTrueTypeFont: Could not set the font size for '" << getResourceName() << "'!");
875 
876  // Windows FNT/FON files do not support Unicode, so restrict the code-point range to either ISO-8859-1 or ASCII,
877  // depending on the font's encoding.
878  if (mCharMap.empty())
879  {
880  // No code points have been specified, so add the printable ASCII range by default.
881  addCodePointRange(0x20, 0x7E);
882 
883  // Additionally, if the font's character set is CP-1252, add the range of non-ASCII 8-bit code points that are
884  // common between CP-1252 and ISO-8859-1; i.e., everything but 0x80 through 0x9F.
885  if (fnt.charset == FT_WinFNT_ID_CP1252)
886  addCodePointRange(0xA0, 0xFF);
887  }
888  else
889  {
890  // Some code points have been specified, so remove anything in the non-printable ASCII range as well as anything
891  // over 8 bits.
892  removeCodePointRange(0, 0x1F);
893  removeCodePointRange(0x100, std::numeric_limits<Char>::max());
894 
895  // Additionally, remove non-ASCII 8-bit code points (plus ASCII DEL, 0x7F). If the font's character set is CP-1252,
896  // remove only the code points that differ between CP-1252 and ISO-8859-1; otherwise, remove all of them.
897  if (fnt.charset == FT_WinFNT_ID_CP1252)
898  removeCodePointRange(0x7F, 0x9F);
899  else
900  removeCodePointRange(0x7F, 0xFF);
901  }
902  }
903 
904  return result;
905  }
906 
907  void ResourceTrueTypeFont::autoWrapGlyphPos(int _glyphWidth, int _texWidth, int _lineHeight, int& _texX, int& _texY) const
908  {
909  if (_glyphWidth > 0 && _texX + mGlyphSpacing + _glyphWidth > _texWidth)
910  {
911  _texX = mGlyphSpacing;
912  _texY += mGlyphSpacing + _lineHeight;
913  }
914  }
915 
916  GlyphInfo ResourceTrueTypeFont::createFaceGlyphInfo(Char _codePoint, int _fontAscent, FT_GlyphSlot _glyph) const
917  {
918  float bearingX = _glyph->metrics.horiBearingX / 64.0f;
919 
920  // The following calculations aren't currently needed but are kept here for future use.
921  // float ascent = _glyph->metrics.horiBearingY / 64.0f;
922  // float descent = (_glyph->metrics.height / 64.0f) - ascent;
923 
924  return GlyphInfo(
925  _codePoint,
926  std::max((float)_glyph->bitmap.width, _glyph->metrics.width / 64.0f),
927  std::max((float)_glyph->bitmap.rows, _glyph->metrics.height / 64.0f),
928  (_glyph->advance.x / 64.0f) - bearingX,
929  bearingX,
930  std::floor(_fontAscent - (_glyph->metrics.horiBearingY / 64.0f) - mOffsetHeight));
931  }
932 
933  int ResourceTrueTypeFont::createGlyph(FT_UInt _glyphIndex, const GlyphInfo& _glyphInfo, GlyphHeightMap& _glyphHeightMap)
934  {
935  int width = (int)std::ceil(_glyphInfo.width);
936  int height = (int)std::ceil(_glyphInfo.height);
937 
938  mCharMap[_glyphInfo.codePoint] = _glyphIndex;
939  GlyphInfo& info = mGlyphMap.insert(GlyphMap::value_type(_glyphInfo.codePoint, _glyphInfo)).first->second;
940  _glyphHeightMap[height].insert(std::make_pair(_glyphIndex, &info));
941 
942  return (width > 0) ? mGlyphSpacing + width : 0;
943  }
944 
945  int ResourceTrueTypeFont::createFaceGlyph(FT_UInt _glyphIndex, Char _codePoint, int _fontAscent, const FT_Face& _ftFace, FT_Int32 _ftLoadFlags, GlyphHeightMap& _glyphHeightMap)
946  {
947  if (mGlyphMap.find(_codePoint) == mGlyphMap.end())
948  {
949  if (FT_Load_Glyph(_ftFace, _glyphIndex, _ftLoadFlags) == 0)
950  return createGlyph(_glyphIndex, createFaceGlyphInfo(_codePoint, _fontAscent, _ftFace->glyph), _glyphHeightMap);
951  else
952  MYGUI_LOG(Warning, "ResourceTrueTypeFont: Cannot load glyph " << _glyphIndex << " for character " << _codePoint << " in font '" << getResourceName() << "'.");
953  }
954  else
955  {
956  mCharMap[_codePoint] = _glyphIndex;
957  }
958 
959  return 0;
960  }
961 
962  template<bool LAMode, bool Antialias>
963  void ResourceTrueTypeFont::renderGlyphs(const GlyphHeightMap& _glyphHeightMap, const FT_Library& _ftLibrary, const FT_Face& _ftFace, FT_Int32 _ftLoadFlags, uint8* _texBuffer, int _texWidth, int _texHeight)
964  {
965  FT_Bitmap ftBitmap;
966  FT_Bitmap_New(&ftBitmap);
967 
968  int texX = mGlyphSpacing, texY = mGlyphSpacing;
969 
970  for (const auto& sameHeightGlyphs : _glyphHeightMap)
971  {
972  int glyphHeight = sameHeightGlyphs.first;
973  for (const auto& glyph : sameHeightGlyphs.second)
974  {
975  GlyphInfo& info = *glyph.second;
976 
977  switch (info.codePoint)
978  {
981  {
982  renderGlyph<LAMode, false, false>(info, charMaskWhite, charMaskBlack, charMask.find(info.codePoint)->second, glyphHeight, _texBuffer, _texWidth, _texHeight, texX, texY);
983 
984  // Manually adjust the glyph's width to zero. This prevents artifacts from appearing at the seams when
985  // rendering multi-character selections.
986  GlyphMap::iterator glyphIter = mGlyphMap.find(info.codePoint);
987  if (glyphIter != mGlyphMap.end())
988  {
989  glyphIter->second.width = 0.0f;
990  glyphIter->second.uvRect.right = glyphIter->second.uvRect.left;
991  }
992  }
993  break;
994 
996  case FontCodeType::Tab:
997  renderGlyph<LAMode, false, false>(info, charMaskWhite, charMaskBlack, charMask.find(info.codePoint)->second, glyphHeight, _texBuffer, _texWidth, _texHeight, texX, texY);
998  break;
999 
1000  default:
1001  if (FT_Load_Glyph(_ftFace, glyph.first, _ftLoadFlags | FT_LOAD_RENDER) == 0)
1002  {
1003  if (_ftFace->glyph->bitmap.buffer != nullptr)
1004  {
1005  uint8* glyphBuffer = nullptr;
1006 
1007  switch (_ftFace->glyph->bitmap.pixel_mode)
1008  {
1009  case FT_PIXEL_MODE_GRAY:
1010  glyphBuffer = _ftFace->glyph->bitmap.buffer;
1011  break;
1012 
1013  case FT_PIXEL_MODE_MONO:
1014  // Convert the monochrome bitmap to 8-bit before rendering it.
1015  if (FT_Bitmap_Convert(_ftLibrary, &_ftFace->glyph->bitmap, &ftBitmap, 1) == 0)
1016  {
1017  // Go through the bitmap and convert all of the nonzero values to 0xFF (white).
1018  for (uint8* p = ftBitmap.buffer, * endP = p + ftBitmap.width * ftBitmap.rows; p != endP; ++p)
1019  *p = *p ? 0xFF : 0;
1020 
1021  glyphBuffer = ftBitmap.buffer;
1022  }
1023  break;
1024  }
1025 
1026  if (glyphBuffer != nullptr)
1027  renderGlyph<LAMode, true, Antialias>(info, charMaskWhite, charMaskWhite, charMaskWhite, glyphHeight, _texBuffer, _texWidth, _texHeight, texX, texY, glyphBuffer);
1028  }
1029  }
1030  else
1031  {
1032  MYGUI_LOG(Warning, "ResourceTrueTypeFont: Cannot render glyph " << glyph.first << " for character " << info.codePoint << " in font '" << getResourceName() << "'.");
1033  }
1034  break;
1035  }
1036  }
1037  }
1038 
1039  FT_Bitmap_Done(_ftLibrary, &ftBitmap);
1040  }
1041 
1042  template<bool LAMode, bool UseBuffer, bool Antialias>
1043  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)
1044  {
1045  int width = (int)std::ceil(_info.width);
1046  int height = (int)std::ceil(_info.height);
1047 
1048  autoWrapGlyphPos(width, _texWidth, _lineHeight, _texX, _texY);
1049 
1050  uint8* dest = _texBuffer + (_texY * _texWidth + _texX) * Pixel<LAMode>::getNumBytes();
1051 
1052  // Calculate how much to advance the destination pointer after each row to get to the start of the next row.
1053  ptrdiff_t destNextRow = (_texWidth - width) * Pixel<LAMode>::getNumBytes();
1054 
1055  if (!mMsdfMode || !UseBuffer)
1056  {
1057  for (int j = height; j > 0; --j)
1058  {
1059  int i;
1060  for (i = width; i > 1; i -= 2)
1061  {
1062  Pixel<LAMode, UseBuffer, Antialias>::set(dest, _luminance0, _alpha, _glyphBuffer);
1063  Pixel<LAMode, UseBuffer, Antialias>::set(dest, _luminance1, _alpha, _glyphBuffer);
1064  }
1065 
1066  if (i > 0)
1067  Pixel<LAMode, UseBuffer, Antialias>::set(dest, _luminance0, _alpha, _glyphBuffer);
1068 
1069  dest += destNextRow;
1070  }
1071  }
1072  else
1073  {
1074  for (int y = 0; y < height; ++y)
1075  {
1076  for (int x = 0; x < width; ++x)
1077  {
1078  for (int i = 0; i < 3; ++i)
1079  {
1080  *dest++ = *_glyphBuffer++;
1081  }
1082  *dest++ = 255;
1083  }
1084 
1085  dest += destNextRow;
1086  }
1087  }
1088 
1089  // Calculate and store the glyph's UV coordinates within the texture.
1090  _info.uvRect.left = (float)_texX / _texWidth; // u1
1091  _info.uvRect.top = (float)_texY / _texHeight; // v1
1092  _info.uvRect.right = (float)(_texX + _info.width) / _texWidth; // u2
1093  _info.uvRect.bottom = (float)(_texY + _info.height) / _texHeight; // v2
1094 
1095  if (width > 0)
1096  _texX += mGlyphSpacing + width;
1097  }
1098 
1099 #ifdef MYGUI_MSDF_FONTS
1100  GlyphInfo ResourceTrueTypeFont::createMsdfFaceGlyphInfo(Char _codePoint, const msdfgen::Shape& _shape, double _advance, int _fontAscent)
1101  {
1102  msdfgen::Shape::Bounds bounds = _shape.getBounds();
1103  double range = mMsdfRange / 2.0;
1104  if (_shape.contours.empty())
1105  {
1106  bounds = {0, 0, 0, 0};
1107  range = 0;
1108  }
1109 
1110  double bearingX = bounds.l;
1111 
1112  return GlyphInfo(
1113  _codePoint,
1114  bounds.r - bounds.l + 2 * range,
1115  bounds.t - bounds.b + 2 * range,
1116  _advance - bearingX + range,
1117  bearingX - range,
1118  std::floor(_fontAscent - bounds.t - mOffsetHeight - range));
1119  }
1120 
1121  int ResourceTrueTypeFont::createMsdfGlyph(const GlyphInfo& _glyphInfo, GlyphHeightMap& _glyphHeightMap)
1122  {
1123  int width = (int)std::ceil(_glyphInfo.width);
1124  int height = (int)std::ceil(_glyphInfo.height);
1125 
1126  mCharMap[_glyphInfo.codePoint] = _glyphInfo.codePoint;
1127  GlyphInfo& info = mGlyphMap.insert(GlyphMap::value_type(_glyphInfo.codePoint, _glyphInfo)).first->second;
1128  _glyphHeightMap[height].insert(std::make_pair(_glyphInfo.codePoint, &info));
1129 
1130  return (width > 0) ? mGlyphSpacing + width : 0;
1131  }
1132 
1133  int ResourceTrueTypeFont::createMsdfFaceGlyph(Char _codePoint, int _fontAscent, msdfgen::FontHandle* _fontHandle, GlyphHeightMap& _glyphHeightMap)
1134  {
1135  if (mGlyphMap.find(_codePoint) == mGlyphMap.end())
1136  {
1137  msdfgen::Shape shape;
1138  double advance;
1139  if (msdfgen::loadGlyph(shape, _fontHandle, _codePoint, &advance))
1140  createMsdfGlyph(createMsdfFaceGlyphInfo(_codePoint, shape, advance, _fontAscent), _glyphHeightMap);
1141  else
1142  MYGUI_LOG(Warning, "ResourceTrueTypeFont: Cannot load msdf glyph for character " << _codePoint << " in font '" << getResourceName() << "'.");
1143  }
1144  else
1145  {
1146  mCharMap[_codePoint] = _codePoint;
1147  }
1148 
1149  return 0;
1150  }
1151 
1152  void ResourceTrueTypeFont::renderMsdfGlyphs(const GlyphHeightMap& _glyphHeightMap, msdfgen::FontHandle* _fontHandle, uint8* _texBuffer, int _texWidth, int _texHeight)
1153  {
1154  int texX = mGlyphSpacing, texY = mGlyphSpacing;
1155 
1156  for (const auto& sameHeightGlyphs : _glyphHeightMap)
1157  {
1158  int glyphHeight = sameHeightGlyphs.first;
1159  for (const auto& glyph : sameHeightGlyphs.second)
1160  {
1161  GlyphInfo& info = *glyph.second;
1162 
1163  switch (info.codePoint)
1164  {
1167  {
1168  renderGlyph<false, false, false>(info, charMaskWhite, charMaskBlack, charMask.find(info.codePoint)->second, glyphHeight, _texBuffer, _texWidth, _texHeight, texX, texY);
1169 
1170  // Manually adjust the glyph's width to zero. This prevents artifacts from appearing at the seams when
1171  // rendering multi-character selections.
1172  GlyphMap::iterator glyphIter = mGlyphMap.find(info.codePoint);
1173  if (glyphIter != mGlyphMap.end())
1174  {
1175  glyphIter->second.width = 0.0f;
1176  glyphIter->second.uvRect.right = glyphIter->second.uvRect.left;
1177  }
1178  }
1179  break;
1180 
1181  case FontCodeType::Cursor:
1182  case FontCodeType::Tab:
1183  renderGlyph<false, false, false>(info, charMaskWhite, charMaskBlack, charMask.find(info.codePoint)->second, glyphHeight, _texBuffer, _texWidth, _texHeight, texX, texY);
1184  break;
1185 
1186  default:
1187  msdfgen::Shape shape;
1188  if (loadGlyph(shape, _fontHandle, info.codePoint))
1189  {
1190  msdfgen::Shape::Bounds bounds = shape.getBounds();
1191  double range = mMsdfRange / 2.0;
1192  if (shape.contours.empty())
1193  {
1194  bounds = {0, 0, 0, 0};
1195  range = 0;
1196  }
1197 
1198  shape.normalize();
1199  edgeColoringSimple(shape, 3.0);
1200 
1201  msdfgen::Bitmap<float, 3> msdf(
1202  std::ceil(bounds.r - bounds.l + 2 * range),
1203  std::ceil(bounds.t - bounds.b + 2 * range));
1204  msdfgen::generateMSDF(msdf, shape, mMsdfRange, 1, msdfgen::Vector2(-bounds.l + range, -bounds.b + range));
1205 // double error = msdfgen::estimateSDFError(
1206 // msdfgen::BitmapConstRef<float, 3>{(float*)msdf, msdf.width(), msdf.height()},
1207 // shape,
1208 // 1,
1209 // msdfgen::Vector2(-bounds.l + range, -bounds.b + range),
1210 // 33);
1211 // if (100000 * error > 1)
1212 // MYGUI_LOG(Warning, "Error for '" << char(info.codePoint) << "' is :" << (int) 100000 * error);
1213 
1214  uint8* glyphBuffer = new uint8[msdf.width() * msdf.height() * 3];
1215  uint8* glyphBufferPointer = glyphBuffer;
1216  for (int y = 0; y < msdf.height(); ++y)
1217  {
1218  for (int x = 0; x < msdf.width(); ++x)
1219  {
1220  for (int i = 0; i < 3; ++i)
1221  {
1222  // upside-down and RGB->BGR
1223  *glyphBufferPointer++ = msdfgen::pixelFloatToByte(msdf(x, msdf.height() - y - 1)[2 - i]);
1224  }
1225  }
1226  }
1227 
1228  renderGlyph<false, true, false>(info, charMaskWhite, charMaskWhite, charMaskWhite, glyphHeight, _texBuffer, _texWidth, _texHeight, texX, texY, glyphBuffer);
1229  delete[] glyphBuffer;
1230  }
1231  else
1232  {
1233  MYGUI_LOG(Warning, "ResourceTrueTypeFont: Cannot render glyph for character " << info.codePoint << " in font '" << getResourceName() << "'.");
1234  }
1235  break;
1236  }
1237  }
1238  }
1239  }
1240 #endif
1241 
1242  void ResourceTrueTypeFont::setSource(const std::string& _value)
1243  {
1244  mSource = _value;
1245  }
1246 
1247  void ResourceTrueTypeFont::setShader(const std::string& _value)
1248  {
1249  mShader = _value;
1250  }
1251 
1252  void ResourceTrueTypeFont::setSize(float _value)
1253  {
1254  mSize = _value;
1255  }
1256 
1257  void ResourceTrueTypeFont::setResolution(unsigned int _value)
1258  {
1259  mResolution = _value;
1260  }
1261 
1262  void ResourceTrueTypeFont::setHinting(const std::string& _value)
1263  {
1264  if (_value == "use_native")
1265  mHinting = HintingUseNative;
1266  else if (_value == "force_auto")
1267  mHinting = HintingForceAuto;
1268  else if (_value == "disable_auto")
1269  mHinting = HintingDisableAuto;
1270  else if (_value == "disable_all")
1271  mHinting = HintingDisableAll;
1272  else
1273  mHinting = HintingUseNative;
1274  }
1275 
1276  void ResourceTrueTypeFont::setAntialias(bool _value)
1277  {
1278  mAntialias = _value;
1279  }
1280 
1281  void ResourceTrueTypeFont::setTabWidth(float _value)
1282  {
1283  mTabWidth = _value;
1284  }
1285 
1286  void ResourceTrueTypeFont::setOffsetHeight(int _value)
1287  {
1288  mOffsetHeight = _value;
1289  }
1290 
1292  {
1293  mSubstituteCodePoint = _value;
1294  }
1295 
1296  void ResourceTrueTypeFont::setDistance(int _value)
1297  {
1298  mGlyphSpacing = _value;
1299  }
1300 
1301  void ResourceTrueTypeFont::setMsdfMode(bool _value)
1302  {
1303 #ifndef MYGUI_MSDF_FONTS
1304  if (_value)
1305  MYGUI_LOG(Error, "MsdfMode flag ignored Define MYGUI_MSDF_FONTS if you need msdf fonts, msdf mode ignored.");
1306 #else
1307  mMsdfMode = _value;
1308 #endif
1309  }
1310 
1311  void ResourceTrueTypeFont::setMsdfRange(int _value)
1312  {
1313  mMsdfRange = _value;
1314  }
1315 
1316 #endif // MYGUI_USE_FREETYPE
1317 
1318 } // namespace MyGUI
#define MYGUI_EXCEPT(dest)
#define MYGUI_LOG(level, text)
static Type firstPO2From(Type _value)
Definition: MyGUI_Bitwise.h:21
virtual void freeData(IDataStream *_data)=0
virtual IDataStream * getData(const std::string &_name) const =0
static DataManager & getInstance()
virtual size_t size()=0
void deserialization(xml::ElementPtr _node, Version _version) override
const std::string & getResourceName() const
virtual void createManual(int _width, int _height, TextureUsage _usage, PixelFormat _format)=0
virtual ITexture * createTexture(const std::string &_name)=0
virtual void destroyTexture(ITexture *_texture)=0
static RenderManager & getInstance()
virtual bool isFormatSupported(PixelFormat _format, TextureUsage _usage)
void setResolution(unsigned int _value)
void textureInvalidate(ITexture *_texture) override
void setSource(const std::string &_value)
void setShader(const std::string &_value)
const GlyphInfo * getGlyphInfo(Char _id) const override
void removeCodePointRange(Char _first, Char _second)
void setHinting(const std::string &_value)
void addCodePointRange(Char _first, Char _second)
ITexture * getTextureFont() const override
std::vector< std::pair< Char, Char > > getCodePointRanges() const
void deserialization(xml::ElementPtr _node, Version _version) override
int parseInt(const std::string &_value)
bool parseBool(const std::string &_value)
unsigned int parseUInt(const std::string &_value)
std::string toString(T p)
std::vector< std::string > split(const std::string &_source, const std::string &_delims="\t\n ")
float parseFloat(const std::string &_value)
Element * ElementPtr
uint8_t uint8
Definition: MyGUI_Types.h:45
unsigned int Char
Definition: MyGUI_Types.h:49