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