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"
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
28namespace 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
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 {
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
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
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
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
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
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
const std::string & getResourceName() const
void deserialization(xml::ElementPtr _node, Version _version) override
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
std::vector< std::string > split(const std::string &_source, const std::string &_delims="\t\n ")
int parseInt(const std::string &_value)
bool parseBool(const std::string &_value)
unsigned int parseUInt(const std::string &_value)
std::string toString(T p)
float parseFloat(const std::string &_value)
Element * ElementPtr
uint8_t uint8
Definition: MyGUI_Types.h:45
unsigned int Char
Definition: MyGUI_Types.h:49