diff --git a/.gitignore b/.gitignore
index b653b7f77..30c2caeb2 100644
--- a/.gitignore
+++ b/.gitignore
@@ -11,7 +11,6 @@ Source/*.Gen.*
Source/*.csproj
/Package_*/
!Source/Engine/Debug
-/Source/Platforms/Editor/Linux/Mono/etc/mono/registry
PackageEditor_Cert.command
PackageEditor_Cert.bat
PackagePlatforms_Cert.bat
@@ -157,4 +156,3 @@ obj/
.idea/
*.code-workspace
omnisharp.json
-Content/Editor/Fonts/NotoSansSC-Regular.flax
diff --git a/Content/Editor/Fonts/NotoSansSC-Regular.flax b/Content/Editor/Fonts/NotoSansSC-Regular.flax
new file mode 100644
index 000000000..39964e6c5
--- /dev/null
+++ b/Content/Editor/Fonts/NotoSansSC-Regular.flax
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:19fa43eb7b31ee3936348b1f271c464c79d7020a21d33e3cdbe54f98c3b14304
+size 10560899
diff --git a/Source/Editor/EditorAssets.cs b/Source/Editor/EditorAssets.cs
index c894abe6b..8b2049ebd 100644
--- a/Source/Editor/EditorAssets.cs
+++ b/Source/Editor/EditorAssets.cs
@@ -54,7 +54,10 @@ namespace FlaxEditor
///
public static string PrimaryFont = "Editor/Fonts/Roboto-Regular";
- public static string CjkFont = "Editor/Fonts/NotoSansSC-Regular";
+ ///
+ /// The secondary (fallback) font to use for missing characters rendering (CJK - Chinese/Japanese/Korean characters).
+ ///
+ public static string FallbackFont = "Editor/Fonts/NotoSansSC-Regular";
///
/// The Inconsolata Regular font.
diff --git a/Source/Editor/GUI/Row.cs b/Source/Editor/GUI/Row.cs
index f75f11922..3e2bb63bd 100644
--- a/Source/Editor/GUI/Row.cs
+++ b/Source/Editor/GUI/Row.cs
@@ -43,9 +43,9 @@ namespace FlaxEditor.GUI
{
Depth = -1;
- var mediumHeight = Style.Current.FontMedium.GetMaxHeight();
- if (Height < mediumHeight)
- Height = mediumHeight + 4;
+ var fontHeight = Style.Current.FontMedium.Height;
+ if (Height < fontHeight)
+ Height = fontHeight + 4;
}
///
diff --git a/Source/Editor/GUI/Timeline/GUI/PositionHandle.cs b/Source/Editor/GUI/Timeline/GUI/PositionHandle.cs
index 3f835a35f..bedb61a5e 100644
--- a/Source/Editor/GUI/Timeline/GUI/PositionHandle.cs
+++ b/Source/Editor/GUI/Timeline/GUI/PositionHandle.cs
@@ -36,16 +36,16 @@ namespace FlaxEditor.GUI.Timeline.GUI
string labelText;
switch (_timeline.TimeShowMode)
{
- case Timeline.TimeShowModes.Frames:
- labelText = _timeline.CurrentFrame.ToString("###0", CultureInfo.InvariantCulture);
- break;
- case Timeline.TimeShowModes.Seconds:
- labelText = _timeline.CurrentTime.ToString("###0.##'s'", CultureInfo.InvariantCulture);
- break;
- case Timeline.TimeShowModes.Time:
- labelText = TimeSpan.FromSeconds(_timeline.CurrentTime).ToString("g");
- break;
- default: throw new ArgumentOutOfRangeException();
+ case Timeline.TimeShowModes.Frames:
+ labelText = _timeline.CurrentFrame.ToString("###0", CultureInfo.InvariantCulture);
+ break;
+ case Timeline.TimeShowModes.Seconds:
+ labelText = _timeline.CurrentTime.ToString("###0.##'s'", CultureInfo.InvariantCulture);
+ break;
+ case Timeline.TimeShowModes.Time:
+ labelText = TimeSpan.FromSeconds(_timeline.CurrentTime).ToString("g");
+ break;
+ default: throw new ArgumentOutOfRangeException();
}
var color = (_timeline.IsMovingPositionHandle ? style.ProgressNormal : style.Foreground).AlphaMultiplied(0.6f);
Matrix3x3.RotationZ(Mathf.PiOverTwo, out var m1);
diff --git a/Source/Editor/Options/InterfaceOptions.cs b/Source/Editor/Options/InterfaceOptions.cs
index af432baa7..6180b5a66 100644
--- a/Source/Editor/Options/InterfaceOptions.cs
+++ b/Source/Editor/Options/InterfaceOptions.cs
@@ -172,9 +172,9 @@ namespace FlaxEditor.Options
set
{
if (value == null)
- _outputLogFont = new FontReference(FlaxEngine.Content.LoadAsyncInternal(EditorAssets.InconsolataRegularFont), 10);
+ _outputLogFont = new FontReference(ConsoleFont, 10);
else if (!value.Font)
- _outputLogFont.Font = FlaxEngine.Content.LoadAsyncInternal(EditorAssets.InconsolataRegularFont);
+ _outputLogFont.Font = ConsoleFont;
else
_outputLogFont = value;
}
@@ -237,8 +237,7 @@ namespace FlaxEditor.Options
public int NumberOfGameClientsToLaunch = 1;
private static FontAsset DefaultFont => FlaxEngine.Content.LoadAsyncInternal(EditorAssets.PrimaryFont);
-
- private static FontAsset ConsoleFont => FlaxEngine.Content.LoadAsyncInternal(EditorAssets.PrimaryFont);
+ private static FontAsset ConsoleFont => FlaxEngine.Content.LoadAsyncInternal(EditorAssets.InconsolataRegularFont);
private FontReference _titleFont = new FontReference(DefaultFont, 18);
private FontReference _largeFont = new FontReference(DefaultFont, 14);
@@ -247,9 +246,10 @@ namespace FlaxEditor.Options
private FontReference _outputLogFont = new FontReference(ConsoleFont, 10);
///
- /// The fallback fonts.
+ /// The list of fallback fonts to use when main text font is missing certain characters. Empty to use fonts from GraphicsSettings.
///
- public FontAsset[] Fallbacks = [FlaxEngine.Content.LoadAsyncInternal(EditorAssets.CjkFont)];
+ [EditorDisplay("Fonts"), EditorOrder(650)]
+ public FontAsset[] FallbackFonts = [FlaxEngine.Content.LoadAsyncInternal(EditorAssets.FallbackFont)];
///
/// Gets or sets the title font for editor UI.
diff --git a/Source/Editor/Options/OptionsModule.cs b/Source/Editor/Options/OptionsModule.cs
index bf35105a5..bb90be6d9 100644
--- a/Source/Editor/Options/OptionsModule.cs
+++ b/Source/Editor/Options/OptionsModule.cs
@@ -3,6 +3,7 @@
using System;
using System.Collections.Generic;
using System.IO;
+using System.Linq;
using FlaxEditor.Content.Settings;
using FlaxEditor.Modules;
using FlaxEngine;
@@ -225,11 +226,11 @@ namespace FlaxEditor.Options
}
}
- var graphicsSetttings = GameSettings.Load();
- if (graphicsSetttings.EnableFontFallback && graphicsSetttings.FallbackFonts == null)
- {
- Render2D.FallbackFonts = graphicsSetttings.FallbackFonts = FontFallbackList.Create(Options.Interface.Fallbacks);
- }
+ // Set fallback fonts
+ var fallbackFonts = Options.Interface.FallbackFonts;
+ if (fallbackFonts == null || fallbackFonts.Length == 0 || fallbackFonts.All(x => x == null))
+ fallbackFonts = GameSettings.Load().FallbackFonts;
+ Font.FallbackFonts = fallbackFonts;
}
///
diff --git a/Source/Editor/Windows/OutputLogWindow.cs b/Source/Editor/Windows/OutputLogWindow.cs
index f168d8d45..6526d7c8a 100644
--- a/Source/Editor/Windows/OutputLogWindow.cs
+++ b/Source/Editor/Windows/OutputLogWindow.cs
@@ -562,12 +562,12 @@ namespace FlaxEditor.Windows
{
switch (match.Groups["level"].Value)
{
- case "error":
- textBlock.Style = _output.ErrorStyle;
- break;
- case "warning":
- textBlock.Style = _output.WarningStyle;
- break;
+ case "error":
+ textBlock.Style = _output.ErrorStyle;
+ break;
+ case "warning":
+ textBlock.Style = _output.WarningStyle;
+ break;
}
textBlock.Tag = new TextBlockTag
{
diff --git a/Source/Editor/Windows/SplashScreen.cpp b/Source/Editor/Windows/SplashScreen.cpp
index cba59191e..92894b537 100644
--- a/Source/Editor/Windows/SplashScreen.cpp
+++ b/Source/Editor/Windows/SplashScreen.cpp
@@ -258,13 +258,13 @@ void SplashScreen::OnDraw()
return;
// Title
- const auto titleLength = _titleFont->MeasureTextInternal(GetTitle());
+ const auto titleLength = _titleFont->MeasureText(GetTitle());
TextLayoutOptions layout;
layout.Bounds = Rectangle(10 * s, 10 * s, width - 10 * s, 50 * s);
layout.HorizontalAlignment = TextAlignment::Near;
layout.VerticalAlignment = TextAlignment::Near;
layout.Scale = Math::Min((width - 20 * s) / titleLength.X, 1.0f);
- Render2D::DrawTextInternal(_titleFont, GetTitle(), Color::White, layout);
+ Render2D::DrawText(_titleFont, GetTitle(), Color::White, layout);
// Subtitle
String subtitle(_quote);
@@ -279,14 +279,14 @@ void SplashScreen::OnDraw()
layout.Scale = 1.0f;
layout.HorizontalAlignment = TextAlignment::Far;
layout.VerticalAlignment = TextAlignment::Far;
- Render2D::DrawTextInternal(_subtitleFont, subtitle, Color::FromRGB(0x8C8C8C), layout);
+ Render2D::DrawText(_subtitleFont, subtitle, Color::FromRGB(0x8C8C8C), layout);
// Additional info
const float infoMargin = 6 * s;
layout.Bounds = Rectangle(infoMargin, lightBarHeight + infoMargin, width - (2 * infoMargin), height - lightBarHeight - (2 * infoMargin));
layout.HorizontalAlignment = TextAlignment::Near;
layout.VerticalAlignment = TextAlignment::Center;
- Render2D::DrawTextInternal(_subtitleFont, _infoText, Color::FromRGB(0xFFFFFF) * 0.9f, layout);
+ Render2D::DrawText(_subtitleFont, _infoText, Color::FromRGB(0xFFFFFF) * 0.9f, layout);
}
bool SplashScreen::HasLoadedFonts() const
diff --git a/Source/Engine/Core/Config/GameSettings.h b/Source/Engine/Core/Config/GameSettings.h
index 675c26bd1..54ad29a7b 100644
--- a/Source/Engine/Core/Config/GameSettings.h
+++ b/Source/Engine/Core/Config/GameSettings.h
@@ -7,8 +7,6 @@
#include "Engine/Core/Types/String.h"
#include "Engine/Core/Collections/Dictionary.h"
-class FontFallbackList;
-
///
/// The main game engine configuration service. Loads and applies game configuration.
///
diff --git a/Source/Engine/Core/Config/GraphicsSettings.h b/Source/Engine/Core/Config/GraphicsSettings.h
index e109a55e4..b639b9e64 100644
--- a/Source/Engine/Core/Config/GraphicsSettings.h
+++ b/Source/Engine/Core/Config/GraphicsSettings.h
@@ -6,7 +6,7 @@
#include "Engine/Graphics/Enums.h"
#include "Engine/Graphics/PostProcessSettings.h"
-class FontFallbackList;
+class FontAsset;
///
/// Graphics rendering settings.
@@ -15,6 +15,7 @@ API_CLASS(sealed, Namespace="FlaxEditor.Content.Settings", NoConstructor) class
{
API_AUTO_SERIALIZATION();
DECLARE_SCRIPTING_TYPE_MINIMAL(GraphicsSettings);
+
public:
///
/// Enables rendering synchronization with the refresh rate of the display device to avoid "tearing" artifacts.
@@ -121,16 +122,10 @@ public:
PostProcessSettings PostProcessSettings;
///
- /// Whether to enable font fallbacking globally.
+ /// The list of fallback fonts used for text rendering. Ignored if empty.
///
- API_FIELD(Attributes = "EditorOrder(12000), EditorDisplay(\"Text Render Settings\", EditorDisplayAttribute.InlineStyle)")
- bool EnableFontFallback = true;
-
- ///
- /// The fallback fonts used for text rendering, ignored if null.
- ///
- API_FIELD(Attributes = "EditorOrder(12005), EditorDisplay(\"Text Render Settings\", EditorDisplayAttribute.InlineStyle)")
- FontFallbackList* FallbackFonts;
+ API_FIELD(Attributes="EditorOrder(5000), EditorDisplay(\"Text\")")
+ Array> FallbackFonts;
private:
///
diff --git a/Source/Engine/Graphics/Graphics.cpp b/Source/Engine/Graphics/Graphics.cpp
index 20f29288b..a9bfef470 100644
--- a/Source/Engine/Graphics/Graphics.cpp
+++ b/Source/Engine/Graphics/Graphics.cpp
@@ -8,7 +8,7 @@
#include "Engine/Core/Config/GraphicsSettings.h"
#include "Engine/Engine/CommandLine.h"
#include "Engine/Engine/EngineService.h"
-#include "Engine/Render2D/Render2D.h"
+#include "Engine/Render2D/Font.h"
bool Graphics::UseVSync = false;
Quality Graphics::AAQuality = Quality::Medium;
@@ -70,9 +70,9 @@ void GraphicsSettings::Apply()
Graphics::GIQuality = GIQuality;
Graphics::PostProcessSettings = ::PostProcessSettings();
Graphics::PostProcessSettings.BlendWith(PostProcessSettings, 1.0f);
-
- Render2D::EnableFontFallback = EnableFontFallback;
- Render2D::FallbackFonts = FallbackFonts;
+#if !USE_EDITOR // OptionsModule handles fallback fonts in Editor
+ Font::FallbackFonts = FallbackFonts;
+#endif
}
void Graphics::DisposeDevice()
diff --git a/Source/Engine/Render2D/FallbackFonts.cpp b/Source/Engine/Render2D/FallbackFonts.cpp
deleted file mode 100644
index 7f81a42bb..000000000
--- a/Source/Engine/Render2D/FallbackFonts.cpp
+++ /dev/null
@@ -1,11 +0,0 @@
-#include "FallbackFonts.h"
-#include "FontManager.h"
-#include "Engine/Core/Math/Math.h"
-
-FontFallbackList::FontFallbackList(const Array& fonts)
- : ManagedScriptingObject(SpawnParams(Guid::New(), Font::TypeInitializer)),
- _fontAssets(fonts)
-{
-
-}
-
diff --git a/Source/Engine/Render2D/FallbackFonts.h b/Source/Engine/Render2D/FallbackFonts.h
deleted file mode 100644
index fb247e4e2..000000000
--- a/Source/Engine/Render2D/FallbackFonts.h
+++ /dev/null
@@ -1,119 +0,0 @@
-#pragma once
-
-#include "Engine/Core/Collections/Array.h"
-#include "Engine/Core/Collections/Dictionary.h"
-#include "Font.h"
-#include "FontAsset.h"
-
-struct TextRange;
-class Font;
-class FontAsset;
-
-///
-/// Defines a list of fonts that can be used as a fallback, ordered by priority.
-///
-API_CLASS(Sealed, NoSpawn) class FLAXENGINE_API FontFallbackList : public ManagedScriptingObject
-{
- DECLARE_SCRIPTING_TYPE_NO_SPAWN(FontFallbackList);
-private:
- Array _fontAssets;
-
- // Cache fallback fonts of various sizes
- Dictionary*> _cache;
-
-public:
- ///
- /// Initializes a new instance of the class.
- ///
- /// The fallback font assets.
- FontFallbackList(const Array& fonts);
-
- ///
- /// Initializes a new instance of the class, exposed for C#.
- ///
- /// The fallback font assets.
- /// The new instance.
- API_FUNCTION() FORCE_INLINE static FontFallbackList* Create(const Array& fonts) {
- return New(fonts);
- }
-
- ///
- /// Get the parent assets of fallback fonts.
- ///
- /// The font assets.
- API_PROPERTY() FORCE_INLINE Array& GetFonts() {
- return _fontAssets;
- }
-
- ///
- /// Set the fallback fonts.
- ///
- /// The parent assets of the new fonts.
- API_PROPERTY() FORCE_INLINE void SetFonts(const Array& val) {
- _fontAssets = val;
- }
-
- ///
- /// Gets the fallback fonts with the given size.
- ///
- /// The size.
- /// The generated fonts.
- API_FUNCTION() FORCE_INLINE Array& GetFontList(float size) {
- Array* result;
- if (_cache.TryGet(size, result)) {
- return *result;
- }
-
- result = New>(_fontAssets.Count());
- auto& arr = *result;
- for (int32 i = 0; i < _fontAssets.Count(); i++)
- {
- arr.Add(_fontAssets[i]->CreateFont(size));
- }
-
- _cache[size] = result;
- return *result;
- }
-
-
- ///
- /// Gets the index of the fallback font that should be used to render the char
- ///
- /// The char.
- /// The primary font.
- /// The number to return if none of the fonts can render.
- /// -1 if char can be rendered with primary font, index if it matches a fallback font.
- API_FUNCTION() FORCE_INLINE int32 GetCharFallbackIndex(Char c, Font* primaryFont = nullptr, int32 missing = -1) {
- if (primaryFont && primaryFont->GetAsset()->ContainsChar(c)) {
- return -1;
- }
-
- int32 fontIndex = 0;
- while (fontIndex < _fontAssets.Count() && _fontAssets[fontIndex] && !_fontAssets[fontIndex]->ContainsChar(c))
- {
- fontIndex++;
- }
-
- if (fontIndex < _fontAssets.Count()) {
- return fontIndex;
-
- }
-
- return missing;
- }
-
- ///
- /// Checks if every font is properly loaded.
- ///
- /// True if every font asset is non-null, otherwise false.
- API_FUNCTION() FORCE_INLINE bool Verify() {
- for (int32 i = 0; i < _fontAssets.Count(); i++)
- {
- if (!_fontAssets[i]) {
- return false;
- }
- }
-
- return true;
- }
-};
diff --git a/Source/Engine/Render2D/Font.cpp b/Source/Engine/Render2D/Font.cpp
index 9a2037b3f..71eca1f59 100644
--- a/Source/Engine/Render2D/Font.cpp
+++ b/Source/Engine/Render2D/Font.cpp
@@ -6,7 +6,8 @@
#include "Engine/Core/Log.h"
#include "Engine/Threading/Threading.h"
#include "IncludeFreeType.h"
-#include "FallbackFonts.h"
+
+Array, HeapAllocation> Font::FallbackFonts;
Font::Font(FontAsset* parentAsset, float size)
: ManagedScriptingObject(SpawnParams(Guid::New(), Font::TypeInitializer))
@@ -33,7 +34,7 @@ Font::~Font()
_asset->_fonts.Remove(this);
}
-void Font::GetCharacter(Char c, FontCharacterEntry& result)
+void Font::GetCharacter(Char c, FontCharacterEntry& result, bool enableFallback)
{
// Try to get the character or cache it if cannot be found
if (!_characters.TryGet(c, result))
@@ -45,6 +46,20 @@ void Font::GetCharacter(Char c, FontCharacterEntry& result)
if (_characters.TryGet(c, result))
return;
+ // Try to use fallback font if character is missing
+ if (enableFallback && !_asset->ContainsChar(c))
+ {
+ for (int32 fallbackIndex = 0; fallbackIndex < FallbackFonts.Count(); fallbackIndex++)
+ {
+ FontAsset* fallbackFont = FallbackFonts.Get()[fallbackIndex].Get();
+ if (fallbackFont && fallbackFont->ContainsChar(c))
+ {
+ fallbackFont->CreateFont(GetSize())->GetCharacter(c, result, enableFallback);
+ return;
+ }
+ }
+ }
+
// Create character cache
FontManager::AddNewEntry(this, c, result);
@@ -88,7 +103,7 @@ void Font::CacheText(const StringView& text)
FontCharacterEntry entry;
for (int32 i = 0; i < text.Length(); i++)
{
- GetCharacter(text[i], entry);
+ GetCharacter(text[i], entry, false);
}
}
@@ -103,26 +118,16 @@ void Font::Invalidate()
_characters.Clear();
}
-float Font::GetMaxHeight(FontFallbackList* fallbacks) const
-{
- float height = GetHeight();
- auto& fallbackFonts = fallbacks->GetFontList(GetSize());
- for (int32 i = 0; i < fallbackFonts.Count(); i++)
- {
- height = Math::Max(height, static_cast(fallbackFonts[i]->GetHeight()));
- }
-
- return height;
-}
-
void Font::ProcessText(const StringView& text, Array& outputLines, const TextLayoutOptions& layout)
{
+ int32 textLength = text.Length();
+ if (textLength == 0)
+ return;
float cursorX = 0;
int32 kerning;
FontLineCache tmpLine;
FontCharacterEntry entry;
FontCharacterEntry previous;
- int32 textLength = text.Length();
float scale = layout.Scale / FontManager::FontScale;
float boundsWidth = layout.Bounds.GetWidth();
float baseLinesDistance = static_cast(_height) * layout.BaseLinesGapScale * scale;
@@ -131,10 +136,6 @@ void Font::ProcessText(const StringView& text, Array& outputLines
tmpLine.FirstCharIndex = 0;
tmpLine.LastCharIndex = -1;
- if (textLength == 0) {
- return;
- }
-
int32 lastWrapCharIndex = INVALID_INDEX;
float lastWrapCharX = 0;
bool lastMoveLine = false;
@@ -146,11 +147,6 @@ void Font::ProcessText(const StringView& text, Array& outputLines
float xAdvance = 0;
int32 nextCharIndex = currentIndex + 1;
- // Submit line if text ends
- if (nextCharIndex == textLength) {
- moveLine = true;
- }
-
// Cache current character
const Char currentChar = text[currentIndex];
const bool isWhitespace = StringUtils::IsWhitespace(currentChar);
@@ -168,6 +164,7 @@ void Font::ProcessText(const StringView& text, Array& outputLines
{
// Break line
moveLine = true;
+ currentIndex++;
tmpLine.LastCharIndex++;
}
else
@@ -178,7 +175,7 @@ void Font::ProcessText(const StringView& text, Array& outputLines
// Get kerning
if (!isWhitespace && previous.IsValid)
{
- kerning = GetKerning(previous.Character, entry.Character);
+ kerning = entry.Font->GetKerning(previous.Character, entry.Character);
}
else
{
@@ -247,8 +244,8 @@ void Font::ProcessText(const StringView& text, Array& outputLines
// Reset line
tmpLine.Location.Y += baseLinesDistance;
- tmpLine.FirstCharIndex = nextCharIndex;
- tmpLine.LastCharIndex = nextCharIndex - 1;
+ tmpLine.FirstCharIndex = currentIndex;
+ tmpLine.LastCharIndex = currentIndex - 1;
cursorX = 0;
lastWrapCharIndex = INVALID_INDEX;
lastWrapCharX = 0;
@@ -260,7 +257,7 @@ void Font::ProcessText(const StringView& text, Array& outputLines
}
// Check if an additional line should be created
- if (text[textLength - 1] == '\n')
+ if (tmpLine.LastCharIndex >= tmpLine.FirstCharIndex || text[textLength - 1] == '\n')
{
// Add line
tmpLine.Size.X = cursorX;
@@ -305,262 +302,7 @@ void Font::ProcessText(const StringView& text, Array& outputLines
}
}
-void Font::ProcessText(FontFallbackList* fallbacks, const StringView& text, Array& outputLines, API_PARAM(Ref) const TextLayoutOptions& layout)
-{
- const Array& fallbackFonts = fallbacks->GetFontList(GetSize());
- float cursorX = 0;
- int32 kerning;
- BlockedTextLineCache tmpLine;
- FontBlockCache tmpBlock;
- FontCharacterEntry entry;
- FontCharacterEntry previous;
- int32 textLength = text.Length();
- float scale = layout.Scale / FontManager::FontScale;
- float boundsWidth = layout.Bounds.GetWidth();
- float baseLinesDistanceScale = layout.BaseLinesGapScale * scale;
-
- tmpBlock.Location = Float2::Zero;
- tmpBlock.Size = Float2::Zero;
- tmpBlock.FirstCharIndex = 0;
- tmpBlock.LastCharIndex = -1;
-
- tmpLine.Location = Float2::Zero;
- tmpLine.Size = Float2::Zero;
- tmpLine.Blocks = Array();
-
- if (textLength == 0) {
- return;
- }
-
- int32 lastWrapCharIndex = INVALID_INDEX;
- float lastWrapCharX = 0;
- bool lastMoveLine = false;
- // The index of the font used by the current block
- int32 currentFontIndex = fallbacks->GetCharFallbackIndex(text[0], this);
- // The maximum font height of the current line
- float maxHeight = 0;
- float maxAscender = 0;
- float lastCursorX = 0;
-
- auto getFont = [&](int32 index)->Font* {
- return index >= 0 ? fallbackFonts[index] : this;
- };
-
- // Process each character to split text into single blocks
- for (int32 currentIndex = 0; currentIndex < textLength;)
- {
- bool moveLine = false;
- bool moveBlock = false;
- float xAdvance = 0;
- int32 nextCharIndex = currentIndex + 1;
-
- // Submit line and block if text ends
- if (nextCharIndex == textLength) {
- moveLine = moveBlock = true;
- }
-
- // Cache current character
- const Char currentChar = text[currentIndex];
- const bool isWhitespace = StringUtils::IsWhitespace(currentChar);
-
- // Check if character can wrap words
- const bool isWrapChar = !StringUtils::IsAlnum(currentChar) || isWhitespace || StringUtils::IsUpper(currentChar) || (currentChar >= 0x3040 && currentChar <= 0x9FFF);
- if (isWrapChar && currentIndex != 0)
- {
- lastWrapCharIndex = currentIndex;
- lastWrapCharX = cursorX;
- }
-
- int32 nextFontIndex = currentFontIndex;
- // Check if it's a newline character
- if (currentChar == '\n')
- {
- // Break line
- moveLine = moveBlock = true;
- tmpBlock.LastCharIndex++;
- }
- else
- {
- // Get character entry
- if (nextCharIndex < textLength) {
- nextFontIndex = fallbacks->GetCharFallbackIndex(text[nextCharIndex], this, currentFontIndex);
- }
-
- // Get character entry
- getFont(currentFontIndex)->GetCharacter(currentChar, entry);
-
- maxHeight = Math::Max(maxHeight,
- static_cast(getFont(currentFontIndex)->GetHeight()));
- maxAscender = Math::Max(maxAscender,
- static_cast(getFont(currentFontIndex)->GetAscender()));
-
- // Move block if the font changes or text ends
- if (nextFontIndex != currentFontIndex || nextCharIndex == textLength) {
- moveBlock = true;
- }
-
- // Get kerning, only when the font hasn't changed
- if (!isWhitespace && previous.IsValid && !moveBlock)
- {
- kerning = getFont(currentFontIndex)->GetKerning(previous.Character, entry.Character);
- }
- else
- {
- kerning = 0;
- }
- previous = entry;
- xAdvance = (kerning + entry.AdvanceX) * scale;
-
- // Check if character fits the line or skip wrapping
- if (cursorX + xAdvance <= boundsWidth || layout.TextWrapping == TextWrapping::NoWrap)
- {
- // Move character
- cursorX += xAdvance;
- tmpBlock.LastCharIndex++;
- }
- else if (layout.TextWrapping == TextWrapping::WrapWords)
- {
- if (lastWrapCharIndex != INVALID_INDEX)
- {
- // Skip moving twice for the same character
- int32 lastLineLastCharIndex = outputLines.HasItems() && outputLines.Last().Blocks.HasItems() ? outputLines.Last().Blocks.Last().LastCharIndex : -10000;
- if (lastLineLastCharIndex == lastWrapCharIndex || lastLineLastCharIndex == lastWrapCharIndex - 1 || lastLineLastCharIndex == lastWrapCharIndex - 2)
- {
- currentIndex = nextCharIndex;
- lastMoveLine = moveLine;
- continue;
- }
-
- // Move line
- const Char wrapChar = text[lastWrapCharIndex];
- moveLine = true;
- moveBlock = tmpBlock.FirstCharIndex < lastWrapCharIndex;
-
- cursorX = lastWrapCharX;
- if (StringUtils::IsWhitespace(wrapChar))
- {
- // Skip whitespaces
- tmpBlock.LastCharIndex = lastWrapCharIndex - 1;
- nextCharIndex = currentIndex = lastWrapCharIndex + 1;
- }
- else
- {
- tmpBlock.LastCharIndex = lastWrapCharIndex - 1;
- nextCharIndex = currentIndex = lastWrapCharIndex;
- }
- }
- }
- else if (layout.TextWrapping == TextWrapping::WrapChars)
- {
- // Move line
- moveLine = true;
- moveBlock = tmpBlock.FirstCharIndex < currentChar;
- nextCharIndex = currentIndex;
-
- // Skip moving twice for the same character
- if (lastMoveLine)
- break;
- }
- }
-
- if (moveBlock) {
- // Add block
- tmpBlock.Size.X = lastCursorX - cursorX;
- tmpBlock.Size.Y = baseLinesDistanceScale * getFont(currentFontIndex)->GetHeight();
- tmpBlock.LastCharIndex = Math::Max(tmpBlock.LastCharIndex, tmpBlock.FirstCharIndex);
- tmpBlock.FallbackFontIndex = currentFontIndex;
- tmpLine.Blocks.Add(tmpBlock);
-
- // Reset block
- tmpBlock.Location.X = cursorX;
- tmpBlock.FirstCharIndex = nextCharIndex;
- tmpBlock.LastCharIndex = nextCharIndex - 1;
-
- currentFontIndex = nextFontIndex;
- lastCursorX = cursorX;
- }
-
- // Check if move to another line
- if (moveLine)
- {
- // Add line
- tmpLine.Size.X = cursorX;
- tmpLine.Size.Y = baseLinesDistanceScale * maxHeight;
- tmpLine.MaxAscender = maxAscender;
- outputLines.Add(tmpLine);
-
- // Reset line
- tmpLine.Blocks.Clear();
- tmpLine.Location.Y += baseLinesDistanceScale * maxHeight;
- cursorX = 0;
- tmpBlock.Location.X = cursorX;
- lastWrapCharIndex = INVALID_INDEX;
- lastWrapCharX = 0;
- previous.IsValid = false;
-
- // Reset max font height
- maxHeight = 0;
- maxAscender = 0;
- lastCursorX = 0;
- }
-
- currentIndex = nextCharIndex;
- lastMoveLine = moveLine;
- }
-
- // Check if an additional line should be created
- if (text[textLength - 1] == '\n')
- {
- // Add line
- tmpLine.Size.X = cursorX;
- tmpLine.Size.Y = baseLinesDistanceScale * maxHeight;
- outputLines.Add(tmpLine);
-
- tmpLine.Location.Y += baseLinesDistanceScale * maxHeight;
- }
-
- // Check amount of lines
- if (outputLines.IsEmpty())
- return;
-
- float totalHeight = tmpLine.Location.Y;
-
- Float2 offset = Float2::Zero;
- if (layout.VerticalAlignment == TextAlignment::Center)
- {
- offset.Y += (layout.Bounds.GetHeight() - totalHeight) * 0.5f;
- }
- else if (layout.VerticalAlignment == TextAlignment::Far)
- {
- offset.Y += layout.Bounds.GetHeight() - totalHeight;
- }
- for (int32 i = 0; i < outputLines.Count(); i++)
- {
- BlockedTextLineCache& line = outputLines[i];
- Float2 rootPos = line.Location + offset;
-
- // Fix upper left line corner to match desire text alignment
- if (layout.HorizontalAlignment == TextAlignment::Center)
- {
- rootPos.X += (layout.Bounds.GetWidth() - line.Size.X) * 0.5f;
- }
- else if (layout.HorizontalAlignment == TextAlignment::Far)
- {
- rootPos.X += layout.Bounds.GetWidth() - line.Size.X;
- }
-
- line.Location = rootPos;
-
- // Align all blocks to center in case they have different heights
- for (int32 j = 0; j < line.Blocks.Count(); j++)
- {
- FontBlockCache& block = line.Blocks[j];
- block.Location.Y += (line.MaxAscender - getFont(block.FallbackFontIndex)->GetAscender()) / 2;
- }
- }
-}
-
-Float2 Font::MeasureTextInternal(const StringView& text, const TextLayoutOptions& layout)
+Float2 Font::MeasureText(const StringView& text, const TextLayoutOptions& layout)
{
// Check if there is no need to do anything
if (text.IsEmpty())
@@ -581,28 +323,7 @@ Float2 Font::MeasureTextInternal(const StringView& text, const TextLayoutOptions
return max;
}
-Float2 Font::MeasureTextInternal(FontFallbackList* fallbacks, const StringView& text, const TextLayoutOptions& layout)
-{
- // Check if there is no need to do anything
- if (text.IsEmpty())
- return Float2::Zero;
-
- // Process text
- Array lines;
- ProcessText(fallbacks, text, lines, layout);
-
- // Calculate bounds
- Float2 max = Float2::Zero;
- for (int32 i = 0; i < lines.Count(); i++)
- {
- const BlockedTextLineCache& line = lines[i];
- max = Float2::Max(max, line.Location + line.Size);
- }
-
- return max;
-}
-
-int32 Font::HitTestTextInternal(const StringView& text, const Float2& location, const TextLayoutOptions& layout)
+int32 Font::HitTestText(const StringView& text, const Float2& location, const TextLayoutOptions& layout)
{
// Check if there is no need to do anything
if (text.Length() <= 0)
@@ -639,7 +360,7 @@ int32 Font::HitTestTextInternal(const StringView& text, const Float2& location,
// Apply kerning
if (!isWhitespace && previous.IsValid)
{
- x += GetKerning(previous.Character, entry.Character);
+ x += entry.Font->GetKerning(previous.Character, entry.Character);
}
previous = entry;
@@ -676,107 +397,7 @@ int32 Font::HitTestTextInternal(const StringView& text, const Float2& location,
return smallestIndex;
}
-int32 Font::HitTestTextInternal(FontFallbackList* fallbacks, const StringView& text, const Float2& location, const TextLayoutOptions& layout)
-{
- // Check if there is no need to do anything
- if (text.Length() <= 0)
- return 0;
-
- // Process text
- const Array& fallbackFonts = fallbacks->GetFontList(GetSize());
- Array lines;
- ProcessText(fallbacks, text, lines, layout);
- ASSERT(lines.HasItems());
- float scale = layout.Scale / FontManager::FontScale;
-
- // Offset position to match lines origin space
- Float2 rootOffset = layout.Bounds.Location + lines.First().Location;
- Float2 testPoint = location - rootOffset;
-
- // Get block which may intersect with the position (it's possible because lines have fixed height)
- int32 lineIndex = 0;
- while (lineIndex < lines.Count())
- {
- if (lines[lineIndex].Location.Y + lines[lineIndex].Size.Y >= location.Y) {
- break;
- }
-
- lineIndex++;
- }
- lineIndex = Math::Clamp(lineIndex, 0, lines.Count() - 1);
- const BlockedTextLineCache& line = lines[lineIndex];
-
- int32 blockIndex = 0;
- while (blockIndex < line.Blocks.Count() - 1)
- {
- if (line.Location.X + line.Blocks[blockIndex + 1].Location.X >= location.X) {
- break;
- }
-
- blockIndex++;
- }
- const FontBlockCache& block = line.Blocks[blockIndex];
- float x = line.Location.X;
-
- // Check all characters in the line to find hit point
- FontCharacterEntry previous;
- FontCharacterEntry entry;
- int32 smallestIndex = INVALID_INDEX;
- float dst, smallestDst = MAX_float;
-
- auto getFont = [&](int32 index)->Font* {
- return index >= 0 ? fallbackFonts[index] : this;
- };
-
- for (int32 currentIndex = block.FirstCharIndex; currentIndex <= block.LastCharIndex; currentIndex++)
- {
- // Cache current character
- const Char currentChar = text[currentIndex];
-
- getFont(block.FallbackFontIndex)->GetCharacter(currentChar, entry);
- const bool isWhitespace = StringUtils::IsWhitespace(currentChar);
-
- // Apply kerning
- if (!isWhitespace && previous.IsValid)
- {
- x += getFont(block.FallbackFontIndex)->GetKerning(previous.Character, entry.Character);
- }
- previous = entry;
-
- // Test
- dst = Math::Abs(testPoint.X - x);
- if (dst < smallestDst)
- {
- // Found closer character
- smallestIndex = currentIndex;
- smallestDst = dst;
- }
- else if (dst > smallestDst)
- {
- // Current char is worse so return the best result
- return smallestIndex;
- }
-
- // Move
- x += entry.AdvanceX * scale;
- }
-
- // Test line end edge
- dst = Math::Abs(testPoint.X - x);
- if (dst < smallestDst)
- {
- // Pointer is behind the last character in the line
- smallestIndex = block.LastCharIndex;
-
- // Fix for last line
- if (lineIndex == lines.Count() - 1)
- smallestIndex++;
- }
-
- return smallestIndex;
-}
-
-Float2 Font::GetCharPositionInternal(const StringView& text, int32 index, const TextLayoutOptions& layout)
+Float2 Font::GetCharPosition(const StringView& text, int32 index, const TextLayoutOptions& layout)
{
// Check if there is no need to do anything
if (text.IsEmpty())
@@ -788,7 +409,7 @@ Float2 Font::GetCharPositionInternal(const StringView& text, int32 index, const
ASSERT(lines.HasItems());
float scale = layout.Scale / FontManager::FontScale;
float baseLinesDistance = static_cast(_height) * layout.BaseLinesGapScale * scale;
- Float2 rootOffset = layout.Bounds.Location;
+ Float2 rootOffset = layout.Bounds.Location + lines.First().Location;
// Find line with that position
FontCharacterEntry previous;
@@ -813,7 +434,7 @@ Float2 Font::GetCharPositionInternal(const StringView& text, int32 index, const
// Apply kerning
if (!isWhitespace && previous.IsValid)
{
- x += GetKerning(previous.Character, entry.Character);
+ x += entry.Font->GetKerning(previous.Character, entry.Character);
}
previous = entry;
@@ -827,71 +448,7 @@ Float2 Font::GetCharPositionInternal(const StringView& text, int32 index, const
}
// Position after last character in the last line
- return rootOffset + Float2(lines.Last().Location.X + lines.Last().Size.X, static_cast((lines.Count() - 1) * baseLinesDistance));
-}
-
-Float2 Font::GetCharPositionInternal(FontFallbackList* fallbacks, const StringView& text, int32 index, const TextLayoutOptions& layout)
-{
- // Check if there is no need to do anything
- if (text.IsEmpty())
- return layout.Bounds.Location;
-
- // Process text
- const Array& fallbackFonts = fallbacks->GetFontList(GetSize());
- Array lines;
- ProcessText(fallbacks, text, lines, layout);
- ASSERT(lines.HasItems());
- float scale = layout.Scale / FontManager::FontScale;
- float baseLinesDistance = layout.BaseLinesGapScale * scale;
- Float2 rootOffset = layout.Bounds.Location;
-
- // Find line with that position
- FontCharacterEntry previous;
- FontCharacterEntry entry;
-
- auto getFont = [&](int32 index)->Font* {
- return index >= 0 ? fallbackFonts[index] : this;
- };
-
- for (int32 lineIndex = 0; lineIndex < lines.Count(); lineIndex++)
- {
- const BlockedTextLineCache& line = lines[lineIndex];
- for (int32 blockIndex = 0; blockIndex < line.Blocks.Count(); blockIndex++)
- {
- const FontBlockCache& block = line.Blocks[blockIndex];
- // Check if desire position is somewhere inside characters in line range
- if (Math::IsInRange(index, block.FirstCharIndex, block.LastCharIndex))
- {
- float x = line.Location.X + block.Location.X;
- float y = line.Location.Y + block.Location.Y;
-
- // Check all characters in the line
- for (int32 currentIndex = block.FirstCharIndex; currentIndex < index; currentIndex++)
- {
- // Cache current character
- const Char currentChar = text[currentIndex];
- getFont(block.FallbackFontIndex)->GetCharacter(currentChar, entry);
- const bool isWhitespace = StringUtils::IsWhitespace(currentChar);
-
- // Apply kerning
- if (!isWhitespace && previous.IsValid)
- {
- x += getFont(block.FallbackFontIndex)->GetKerning(previous.Character, entry.Character);
- }
- previous = entry;
-
- // Move
- x += entry.AdvanceX * scale;
- }
-
- // Upper left corner of the character
- return rootOffset + Float2(x, y);
- }
- }
- }
-
- // Position after last character in the last line
- return rootOffset + Float2(lines.Last().Location.X + lines.Last().Size.X, lines.Last().Location.Y);
+ return rootOffset + Float2(lines.Last().Size.X, static_cast((lines.Count() - 1) * baseLinesDistance));
}
void Font::FlushFaceSize() const
diff --git a/Source/Engine/Render2D/Font.h b/Source/Engine/Render2D/Font.h
index 1fb41d032..cd92103cb 100644
--- a/Source/Engine/Render2D/Font.h
+++ b/Source/Engine/Render2D/Font.h
@@ -8,12 +8,9 @@
#include "Engine/Content/AssetReference.h"
#include "Engine/Scripting/ScriptingObject.h"
#include "TextLayoutOptions.h"
-#include "Render2D.h"
class FontAsset;
-class FontFallbackList;
struct FontTextureAtlasSlot;
-struct BlockedTextLineCache;
// The default DPI that engine is using
#define DefaultDPI 96
@@ -38,7 +35,7 @@ API_STRUCT(NoDefault) struct TextRange
///
/// Gets the range length.
///
- int32 Length() const
+ FORCE_INLINE int32 Length() const
{
return EndIndex - StartIndex;
}
@@ -46,7 +43,7 @@ API_STRUCT(NoDefault) struct TextRange
///
/// Gets a value indicating whether range is empty.
///
- bool IsEmpty() const
+ FORCE_INLINE bool IsEmpty() const
{
return (EndIndex - StartIndex) <= 0;
}
@@ -56,7 +53,7 @@ API_STRUCT(NoDefault) struct TextRange
///
/// The index.
/// true if range contains the specified character index; otherwise, false.
- bool Contains(int32 index) const
+ FORCE_INLINE bool Contains(int32 index) const
{
return index >= StartIndex && index < EndIndex;
}
@@ -122,74 +119,6 @@ struct TIsPODType
enum { Value = true };
};
-///
-/// The font block info generated during text processing.
-/// A block means a range of text that belongs to the same line and can be rendered with the same font.
-///
-API_STRUCT(NoDefault) struct FontBlockCache
-{
- DECLARE_SCRIPTING_TYPE_MINIMAL(FontBlockCache);
-
- ///
- /// The root position of the block (upper left corner), relative to line.
- ///
- API_FIELD() Float2 Location;
-
- ///
- /// The size of the current block
- ///
- API_FIELD() Float2 Size;
-
- ///
- /// The first character index (from the input text).
- ///
- API_FIELD() int32 FirstCharIndex;
-
- ///
- /// The last character index (from the input text), inclusive.
- ///
- API_FIELD() int32 LastCharIndex;
-
- ///
- /// Indicates the fallback font to render this block with, -1 if doesn't require fallback.
- ///
- API_FIELD() int32 FallbackFontIndex;
-};
-
-template<>
-struct TIsPODType
-{
- enum { Value = true };
-};
-
-///
-/// Line of font blocks info generated during text processing.
-///
-API_STRUCT(NoDefault) struct BlockedTextLineCache
-{
- DECLARE_SCRIPTING_TYPE_MINIMAL(BlockedTextLineCache);
-
- ///
- /// The root position of the line (upper left corner).
- ///
- API_FIELD() Float2 Location;
-
- ///
- /// The line bounds (width and height).
- ///
- API_FIELD() Float2 Size;
-
- ///
- /// The maximum ascender of the line.
- ///
- API_FIELD() float MaxAscender;
-
- ///
- /// The blocks that belongs to this line
- ///
- API_FIELD() Array Blocks;
-};
-
// Font glyph metrics:
//
// xmin xmax
@@ -281,6 +210,11 @@ API_STRUCT(NoDefault) struct FontCharacterEntry
/// The slot in texture atlas, containing the pixel data of the glyph.
///
API_FIELD() const FontTextureAtlasSlot* Slot;
+
+ ///
+ /// The owner font.
+ ///
+ API_FIELD() const class Font* Font;
};
template<>
@@ -296,8 +230,8 @@ API_CLASS(Sealed, NoSpawn) class FLAXENGINE_API Font : public ManagedScriptingOb
{
DECLARE_SCRIPTING_TYPE_NO_SPAWN(Font);
friend FontAsset;
-private:
+private:
FontAsset* _asset;
float _size;
int32 _height;
@@ -309,7 +243,6 @@ private:
mutable Dictionary _kerningTable;
public:
-
///
/// Initializes a new instance of the class.
///
@@ -323,6 +256,10 @@ public:
~Font();
public:
+ ///
+ /// The active fallback fonts.
+ ///
+ API_FIELD() static Array, HeapAllocation> FallbackFonts;
///
/// Gets parent font asset that contains font family used by this font.
@@ -373,13 +310,13 @@ public:
}
public:
-
///
/// Gets character entry.
///
/// The character.
/// The output character entry.
- void GetCharacter(Char c, FontCharacterEntry& result);
+ /// True if fallback to secondary font when the primary font doesn't contains this character.
+ void GetCharacter(Char c, FontCharacterEntry& result, bool enableFallback = true);
///
/// Gets the kerning amount for a pair of characters.
@@ -401,33 +338,8 @@ public:
API_FUNCTION() void Invalidate();
public:
-
///
- /// Gets the maximum height among the font and the fallback fonts.
- ///
- /// The fallback fonts.
- /// The maximum height.
- API_FUNCTION() float GetMaxHeight(FontFallbackList* fallbacks) const;
-
- ///
- /// Gets the maximum height among the font and the fallback fonts, uses the default font defined in .
- ///
- /// The fallback fonts.
- /// The maximum height.
- API_FUNCTION() FORCE_INLINE float GetMaxHeight() const
- {
- if (Render2D::EnableFontFallback && Render2D::FallbackFonts)
- {
- return GetMaxHeight(Render2D::FallbackFonts);
- }
- else
- {
- return GetHeight();
- }
- }
-
- ///
- /// Processes text to get cached lines for rendering, with font fallbacking disabled.
+ /// Processes text to get cached lines for rendering.
///
/// The input text.
/// The layout properties.
@@ -435,12 +347,12 @@ public:
void ProcessText(const StringView& text, Array& outputLines, API_PARAM(Ref) const TextLayoutOptions& layout);
///
- /// Processes text to get cached lines for rendering, with font fallbacking disabled.
+ /// Processes text to get cached lines for rendering.
///
/// The input text.
/// The layout properties.
/// The output lines list.
- API_FUNCTION() FORCE_INLINE Array ProcessText(const StringView& text, API_PARAM(Ref) const TextLayoutOptions& layout)
+ API_FUNCTION() Array ProcessText(const StringView& text, API_PARAM(Ref) const TextLayoutOptions& layout)
{
Array lines;
ProcessText(text, lines, layout);
@@ -448,13 +360,13 @@ public:
}
///
- /// Processes text to get cached lines for rendering, with font fallbacking disabled.
+ /// Processes text to get cached lines for rendering.
///
/// The input text.
/// The input text range (substring range of the input text parameter).
/// The layout properties.
/// The output lines list.
- API_FUNCTION() FORCE_INLINE Array ProcessText(const StringView& text, API_PARAM(Ref) const TextRange& textRange, API_PARAM(Ref) const TextLayoutOptions& layout)
+ API_FUNCTION() Array ProcessText(const StringView& text, API_PARAM(Ref) const TextRange& textRange, API_PARAM(Ref) const TextLayoutOptions& layout)
{
Array lines;
ProcessText(textRange.Substring(text), lines, layout);
@@ -462,7 +374,7 @@ public:
}
///
- /// Processes text to get cached lines for rendering, with font fallbacking disabled.
+ /// Processes text to get cached lines for rendering.
///
/// The input text.
/// The output lines list.
@@ -472,7 +384,7 @@ public:
}
///
- /// Processes text to get cached lines for rendering, with font fallbacking disabled.
+ /// Processes text to get cached lines for rendering.
///
/// The input text.
/// The input text range (substring range of the input text parameter).
@@ -483,349 +395,81 @@ public:
}
///
- /// Processes text to get cached lines for rendering, using custom fallback options.
- ///
- /// The input text.
- /// The layout properties.
- /// The output lines list.
- void ProcessText(FontFallbackList* fallbacks, const StringView& text, Array& outputLines, API_PARAM(Ref) const TextLayoutOptions& layout);
-
- ///
- /// Processes text to get cached lines for rendering, using custom fallback options.
- ///
- /// The input text.
- /// The layout properties.
- /// The output lines list.
- API_FUNCTION() FORCE_INLINE Array ProcessText(FontFallbackList* fallbacks, const StringView& text, API_PARAM(Ref) const TextLayoutOptions& layout)
- {
- Array lines;
- ProcessText(fallbacks, text, lines, layout);
- return lines;
- }
-
- ///
- /// Processes text to get cached lines for rendering, using custom fallback options.
- ///
- /// The input text.
- /// The input text range (substring range of the input text parameter).
- /// The layout properties.
- /// The output lines list.
- API_FUNCTION() FORCE_INLINE Array ProcessText(FontFallbackList* fallbacks, const StringView& text, API_PARAM(Ref) const TextRange& textRange, API_PARAM(Ref) const TextLayoutOptions& layout)
- {
- Array lines;
- ProcessText(fallbacks, textRange.Substring(text), lines, layout);
- return lines;
- }
-
- ///
- /// Processes text to get cached lines for rendering, using custom fallback options.
- ///
- /// The input text.
- /// The output lines list.
- API_FUNCTION() FORCE_INLINE Array ProcessText(FontFallbackList* fallbacks, const StringView& text)
- {
- return ProcessText(fallbacks, text, TextLayoutOptions());
- }
-
- ///
- /// Processes text to get cached lines for rendering, using custom fallback options.
- ///
- /// The input text.
- /// The input text range (substring range of the input text parameter).
- /// The output lines list.
- API_FUNCTION() FORCE_INLINE Array ProcessText(FontFallbackList* fallbacks, const StringView& text, API_PARAM(Ref) const TextRange& textRange)
- {
- return ProcessText(fallbacks, textRange.Substring(text), TextLayoutOptions());
- }
-
- ///
- /// Measures minimum size of the rectangle that will be needed to draw given text, with font fallbacking disabled.
+ /// Measures minimum size of the rectangle that will be needed to draw given text.
///
/// The input text to test.
/// The layout properties.
/// The minimum size for that text and fot to render properly.
- API_FUNCTION() Float2 MeasureTextInternal(const StringView& text, API_PARAM(Ref) const TextLayoutOptions& layout);
+ API_FUNCTION() Float2 MeasureText(const StringView& text, API_PARAM(Ref) const TextLayoutOptions& layout);
///
- /// Measures minimum size of the rectangle that will be needed to draw given text, with font fallbacking disabled.
+ /// Measures minimum size of the rectangle that will be needed to draw given text.
///
/// The input text to test.
/// The input text range (substring range of the input text parameter).
/// The layout properties.
/// The minimum size for that text and fot to render properly.
- API_FUNCTION() FORCE_INLINE Float2 MeasureTextInternal(const StringView& text, API_PARAM(Ref) const TextRange& textRange, API_PARAM(Ref) const TextLayoutOptions& layout)
+ API_FUNCTION() Float2 MeasureText(const StringView& text, API_PARAM(Ref) const TextRange& textRange, API_PARAM(Ref) const TextLayoutOptions& layout)
{
- return MeasureTextInternal(textRange.Substring(text), layout);
+ return MeasureText(textRange.Substring(text), layout);
}
///
- /// Measures minimum size of the rectangle that will be needed to draw given text, with font fallbacking disabled.
- /// .
- /// The input text to test.
- /// The minimum size for that text and fot to render properly.
- API_FUNCTION() FORCE_INLINE Float2 MeasureTextInternal(const StringView& text)
- {
- return MeasureTextInternal(text, TextLayoutOptions());
- }
-
- ///
- /// Measures minimum size of the rectangle that will be needed to draw given text, with font fallbacking disabled.
- /// .
- /// The input text to test.
- /// The input text range (substring range of the input text parameter).
- /// The minimum size for that text and fot to render properly.
- API_FUNCTION() FORCE_INLINE Float2 MeasureTextInternal(const StringView& text, API_PARAM(Ref) const TextRange& textRange)
- {
- return MeasureTextInternal(textRange.Substring(text), TextLayoutOptions());
- }
-
- ///
- /// Measures minimum size of the rectangle that will be needed to draw given text, using custom fallback options.
- ///
- /// The input text to test.
- /// The layout properties.
- /// The minimum size for that text and fot to render properly.
- API_FUNCTION() Float2 MeasureTextInternal(FontFallbackList* fallbacks, const StringView& text, API_PARAM(Ref) const TextLayoutOptions& layout);
-
- ///
- /// Measures minimum size of the rectangle that will be needed to draw given text, using custom fallback options.
- ///
- /// The input text to test.
- /// The input text range (substring range of the input text parameter).
- /// The layout properties.
- /// The minimum size for that text and fot to render properly.
- API_FUNCTION() FORCE_INLINE Float2 MeasureTextInternal(FontFallbackList* fallbacks, const StringView& text, API_PARAM(Ref) const TextRange& textRange, API_PARAM(Ref) const TextLayoutOptions& layout)
- {
- return MeasureTextInternal(fallbacks, textRange.Substring(text), layout);
- }
-
- ///
- /// Measures minimum size of the rectangle that will be needed to draw given text, using custom fallback options.
- /// .
- /// The input text to test.
- /// The minimum size for that text and fot to render properly.
- API_FUNCTION() FORCE_INLINE Float2 MeasureTextInternal(FontFallbackList* fallbacks, const StringView& text)
- {
- return MeasureTextInternal(fallbacks, text, TextLayoutOptions());
- }
-
- ///
- /// Measures minimum size of the rectangle that will be needed to draw given text, using custom fallback options.
- /// .
- /// The input text to test.
- /// The input text range (substring range of the input text parameter).
- /// The minimum size for that text and fot to render properly.
- API_FUNCTION() FORCE_INLINE Float2 MeasureTextInternal(FontFallbackList* fallbacks, const StringView& text, API_PARAM(Ref) const TextRange& textRange)
- {
- return MeasureTextInternal(fallbacks, textRange.Substring(text), TextLayoutOptions());
- }
-
- ///
- /// Measures minimum size of the rectangle that will be needed to draw given text, follows the fallback settings defined in .
- ///
- /// The input text to test.
- /// The layout properties.
- /// The minimum size for that text and fot to render properly.
- API_FUNCTION() FORCE_INLINE Float2 MeasureText(const StringView& text, API_PARAM(Ref) const TextLayoutOptions& layout) {
- if (Render2D::EnableFontFallback && Render2D::FallbackFonts) {
- return MeasureTextInternal(Render2D::FallbackFonts, text, layout);
- }
- else {
- return MeasureTextInternal(text, layout);
- }
- }
-
- ///
- /// Measures minimum size of the rectangle that will be needed to draw given text, follows the fallback settings defined in .
- ///
- /// The input text to test.
- /// The input text range (substring range of the input text parameter).
- /// The layout properties.
- /// The minimum size for that text and fot to render properly.
- API_FUNCTION() FORCE_INLINE Float2 MeasureText(const StringView& text, API_PARAM(Ref) const TextRange& textRange, API_PARAM(Ref) const TextLayoutOptions& layout)
- {
- if (Render2D::EnableFontFallback && Render2D::FallbackFonts) {
- return MeasureTextInternal(Render2D::FallbackFonts, textRange.Substring(text), layout);
- }
- else {
- return MeasureTextInternal(textRange.Substring(text), layout);
- }
- }
-
- ///
- /// Measures minimum size of the rectangle that will be needed to draw given text, follows the fallback settings defined in .
+ /// Measures minimum size of the rectangle that will be needed to draw given text
/// .
/// The input text to test.
/// The minimum size for that text and fot to render properly.
API_FUNCTION() FORCE_INLINE Float2 MeasureText(const StringView& text)
{
- if (Render2D::EnableFontFallback && Render2D::FallbackFonts) {
- return MeasureTextInternal(Render2D::FallbackFonts, text, TextLayoutOptions());
- }
- else {
- return MeasureTextInternal(text, TextLayoutOptions());
- }
+ return MeasureText(text, TextLayoutOptions());
}
///
- /// Measures minimum size of the rectangle that will be needed to draw given text, follows the fallback settings defined in .
+ /// Measures minimum size of the rectangle that will be needed to draw given text
/// .
/// The input text to test.
/// The input text range (substring range of the input text parameter).
/// The minimum size for that text and fot to render properly.
API_FUNCTION() FORCE_INLINE Float2 MeasureText(const StringView& text, API_PARAM(Ref) const TextRange& textRange)
{
- if (Render2D::EnableFontFallback && Render2D::FallbackFonts) {
- return MeasureTextInternal(Render2D::FallbackFonts, textRange.Substring(text), TextLayoutOptions());
- }
- else {
- return MeasureTextInternal(textRange.Substring(text), TextLayoutOptions());
- }
+ return MeasureText(textRange.Substring(text), TextLayoutOptions());
}
///
- /// Calculates hit character index at given location, with font fallbacking disabled.
- ///
- /// The input text to test.
- /// The input location to test.
- /// The text layout properties.
- /// The selected character position index (can be equal to text length if location is outside of the layout rectangle).
- API_FUNCTION() int32 HitTestTextInternal(const StringView& text, const Float2& location, API_PARAM(Ref) const TextLayoutOptions& layout);
-
- ///
- /// Calculates hit character index at given location, with font fallbacking disabled.
+ /// Calculates hit character index at given location.
///
/// The input text to test.
/// The input text range (substring range of the input text parameter).
/// The input location to test.
/// The text layout properties.
/// The selected character position index (can be equal to text length if location is outside of the layout rectangle).
- API_FUNCTION() FORCE_INLINE int32 HitTestTextInternal(const StringView& text, API_PARAM(Ref) const TextRange& textRange, const Float2& location, API_PARAM(Ref) const TextLayoutOptions& layout)
+ API_FUNCTION() int32 HitTestText(const StringView& text, API_PARAM(Ref) const TextRange& textRange, const Float2& location, API_PARAM(Ref) const TextLayoutOptions& layout)
{
- return HitTestTextInternal(textRange.Substring(text), location, layout);
+ return HitTestText(textRange.Substring(text), location, layout);
}
///
- /// Calculates hit character index at given location, with font fallbacking disabled.
- ///
- /// The input text to test.
- /// The input location to test.
- /// The selected character position index (can be equal to text length if location is outside of the layout rectangle).
- API_FUNCTION() FORCE_INLINE int32 HitTestTextInternal(const StringView& text, const Float2& location)
- {
- return HitTestTextInternal(text, location, TextLayoutOptions());
- }
-
- ///
- /// Calculates hit character index at given location, with font fallbacking disabled.
- ///
- /// The input text to test.
- /// The input text range (substring range of the input text parameter).
- /// The input location to test.
- /// The selected character position index (can be equal to text length if location is outside of the layout rectangle).
- API_FUNCTION() FORCE_INLINE int32 HitTestTextInternal(const StringView& text, API_PARAM(Ref) const TextRange& textRange, const Float2& location)
- {
- return HitTestTextInternal(textRange.Substring(text), location, TextLayoutOptions());
- }
-
- ///
- /// Calculates hit character index at given location, using custom fallback options.
+ /// Calculates hit character index at given location.
///
/// The input text to test.
/// The input location to test.
/// The text layout properties.
/// The selected character position index (can be equal to text length if location is outside of the layout rectangle).
- API_FUNCTION() int32 HitTestTextInternal(FontFallbackList* fallbacks, const StringView& text, const Float2& location, API_PARAM(Ref) const TextLayoutOptions& layout);
+ API_FUNCTION() int32 HitTestText(const StringView& text, const Float2& location, API_PARAM(Ref) const TextLayoutOptions& layout);
///
- /// Calculates hit character index at given location, using custom fallback options.
- ///
- /// The input text to test.
- /// The input text range (substring range of the input text parameter).
- /// The input location to test.
- /// The text layout properties.
- /// The selected character position index (can be equal to text length if location is outside of the layout rectangle).
- API_FUNCTION() FORCE_INLINE int32 HitTestTextInternal(FontFallbackList* fallbacks, const StringView& text, API_PARAM(Ref) const TextRange& textRange, const Float2& location, API_PARAM(Ref) const TextLayoutOptions& layout)
- {
- return HitTestTextInternal(fallbacks, textRange.Substring(text), location, layout);
- }
-
- ///
- /// Calculates hit character index at given location, using custom fallback options.
- ///
- /// The input text to test.
- /// The input location to test.
- /// The selected character position index (can be equal to text length if location is outside of the layout rectangle).
- API_FUNCTION() FORCE_INLINE int32 HitTestTextInternal(FontFallbackList* fallbacks, const StringView& text, const Float2& location)
- {
- return HitTestTextInternal(fallbacks, text, location, TextLayoutOptions());
- }
-
- ///
- /// Calculates hit character index at given location, using custom fallback options.
- ///
- /// The input text to test.
- /// The input text range (substring range of the input text parameter).
- /// The input location to test.
- /// The selected character position index (can be equal to text length if location is outside of the layout rectangle).
- API_FUNCTION() FORCE_INLINE int32 HitTestTextInternal(FontFallbackList* fallbacks, const StringView& text, API_PARAM(Ref) const TextRange& textRange, const Float2& location)
- {
- return HitTestTextInternal(fallbacks, textRange.Substring(text), location, TextLayoutOptions());
- }
-
- ///
- /// Calculates hit character index at given location, follows the fallback settings defined in .
- ///
- /// The input text to test.
- /// The input location to test.
- /// The text layout properties.
- /// The selected character position index (can be equal to text length if location is outside of the layout rectangle).
- API_FUNCTION() FORCE_INLINE int32 HitTestText(const StringView& text, const Float2& location, API_PARAM(Ref) const TextLayoutOptions& layout) {
- if (Render2D::EnableFontFallback && Render2D::FallbackFonts) {
- return HitTestTextInternal(Render2D::FallbackFonts, text, location, layout);
- }
- else {
- return HitTestTextInternal(text, location, layout);
- }
- }
-
- ///
- /// Calculates hit character index at given location, follows the fallback settings defined in .
- ///
- /// The input text to test.
- /// The input text range (substring range of the input text parameter).
- /// The input location to test.
- /// The text layout properties.
- /// The selected character position index (can be equal to text length if location is outside of the layout rectangle).
- API_FUNCTION() FORCE_INLINE int32 HitTestText(const StringView& text, API_PARAM(Ref) const TextRange& textRange, const Float2& location, API_PARAM(Ref) const TextLayoutOptions& layout)
- {
- if (Render2D::EnableFontFallback && Render2D::FallbackFonts) {
- return HitTestTextInternal(Render2D::FallbackFonts, textRange.Substring(text), location, layout);
- }
- else {
- return HitTestTextInternal(textRange.Substring(text), location, layout);
- }
-
- }
-
- ///
- /// Calculates hit character index at given location, follows the fallback settings defined in .
+ /// Calculates hit character index at given location.
///
/// The input text to test.
/// The input location to test.
/// The selected character position index (can be equal to text length if location is outside of the layout rectangle).
API_FUNCTION() FORCE_INLINE int32 HitTestText(const StringView& text, const Float2& location)
{
- if (Render2D::EnableFontFallback && Render2D::FallbackFonts) {
- return HitTestTextInternal(Render2D::FallbackFonts, text, location, TextLayoutOptions());
- }
- else {
- return HitTestTextInternal(text, location, TextLayoutOptions());
- }
+ return HitTestText(text, location, TextLayoutOptions());
}
///
- /// Calculates hit character index at given location, follows the fallback settings defined in .
+ /// Calculates hit character index at given location.
///
/// The input text to test.
/// The input text range (substring range of the input text parameter).
@@ -833,156 +477,44 @@ public:
/// The selected character position index (can be equal to text length if location is outside of the layout rectangle).
API_FUNCTION() FORCE_INLINE int32 HitTestText(const StringView& text, API_PARAM(Ref) const TextRange& textRange, const Float2& location)
{
- if (Render2D::EnableFontFallback && Render2D::FallbackFonts) {
- return HitTestTextInternal(Render2D::FallbackFonts, textRange.Substring(text), location, TextLayoutOptions());
- }
- else {
- return HitTestTextInternal(textRange.Substring(text), location, TextLayoutOptions());
- }
+ return HitTestText(textRange.Substring(text), location, TextLayoutOptions());
}
///
- /// Calculates character position for given text and character index, with font fallbacking disabled.
+ /// Calculates character position for given text and character index.
///
/// The input text to test.
/// The text position to get coordinates of.
/// The text layout properties.
/// The character position (upper left corner which can be used for a caret position).
- API_FUNCTION() Float2 GetCharPositionInternal(const StringView& text, int32 index, API_PARAM(Ref) const TextLayoutOptions& layout);
+ API_FUNCTION() Float2 GetCharPosition(const StringView& text, int32 index, API_PARAM(Ref) const TextLayoutOptions& layout);
///
- /// Calculates character position for given text and character index, with font fallbacking disabled.
+ /// Calculates character position for given text and character index.
///
/// The input text to test.
/// The input text range (substring range of the input text parameter).
/// The text position to get coordinates of.
/// The text layout properties.
/// The character position (upper left corner which can be used for a caret position).
- API_FUNCTION() FORCE_INLINE Float2 GetCharPositionInternal(const StringView& text, API_PARAM(Ref) const TextRange& textRange, int32 index, API_PARAM(Ref) const TextLayoutOptions& layout)
+ API_FUNCTION() Float2 GetCharPosition(const StringView& text, API_PARAM(Ref) const TextRange& textRange, int32 index, API_PARAM(Ref) const TextLayoutOptions& layout)
{
- return GetCharPositionInternal(textRange.Substring(text), index, layout);
+ return GetCharPosition(textRange.Substring(text), index, layout);
}
///
- /// Calculates character position for given text and character index, with font fallbacking disabled.
- ///
- /// The input text to test.
- /// The text position to get coordinates of.
- /// The character position (upper left corner which can be used for a caret position).
- API_FUNCTION() FORCE_INLINE Float2 GetCharPositionInternal(const StringView& text, int32 index)
- {
- return GetCharPositionInternal(text, index, TextLayoutOptions());
- }
-
- ///
- /// Calculates character position for given text and character index, with font fallbacking disabled.
- ///
- /// The input text to test.
- /// The input text range (substring range of the input text parameter).
- /// The text position to get coordinates of.
- /// The character position (upper left corner which can be used for a caret position).
- API_FUNCTION() FORCE_INLINE Float2 GetCharPositionInternal(const StringView& text, API_PARAM(Ref) const TextRange& textRange, int32 index)
- {
- return GetCharPositionInternal(textRange.Substring(text), index, TextLayoutOptions());
- }
-
- ///
- /// Calculates character position for given text and character index, using custom fallback options.
- ///
- /// The input text to test.
- /// The text position to get coordinates of.
- /// The text layout properties.
- /// The character position (upper left corner which can be used for a caret position).
- API_FUNCTION() Float2 GetCharPositionInternal(FontFallbackList* fallbacks, const StringView& text, int32 index, API_PARAM(Ref) const TextLayoutOptions& layout);
-
- ///
- /// Calculates character position for given text and character index, using custom fallback options.
- ///
- /// The input text to test.
- /// The input text range (substring range of the input text parameter).
- /// The text position to get coordinates of.
- /// The text layout properties.
- /// The character position (upper left corner which can be used for a caret position).
- API_FUNCTION() FORCE_INLINE Float2 GetCharPositionInternal(FontFallbackList* fallbacks, const StringView& text, API_PARAM(Ref) const TextRange& textRange, int32 index, API_PARAM(Ref) const TextLayoutOptions& layout)
- {
- return GetCharPositionInternal(fallbacks, textRange.Substring(text), index, layout);
- }
-
- ///
- /// Calculates character position for given text and character index, using custom fallback options.
- ///
- /// The input text to test.
- /// The text position to get coordinates of.
- /// The character position (upper left corner which can be used for a caret position).
- API_FUNCTION() FORCE_INLINE Float2 GetCharPositionInternal(FontFallbackList* fallbacks, const StringView& text, int32 index)
- {
- return GetCharPositionInternal(fallbacks, text, index, TextLayoutOptions());
- }
-
- ///
- /// Calculates character position for given text and character index, using custom fallback options.
- ///
- /// The input text to test.
- /// The input text range (substring range of the input text parameter).
- /// The text position to get coordinates of.
- /// The character position (upper left corner which can be used for a caret position).
- API_FUNCTION() FORCE_INLINE Float2 GetCharPositionInternal(FontFallbackList* fallbacks, const StringView& text, API_PARAM(Ref) const TextRange& textRange, int32 index)
- {
- return GetCharPositionInternal(fallbacks, textRange.Substring(text), index, TextLayoutOptions());
- }
-
- ///
- /// Calculates character position for given text and character index, follows the fallback settings defined in .
- ///
- /// The input text to test.
- /// The text position to get coordinates of.
- /// The text layout properties.
- /// The character position (upper left corner which can be used for a caret position).
- API_FUNCTION() FORCE_INLINE Float2 GetCharPosition(const StringView& text, int32 index, API_PARAM(Ref) const TextLayoutOptions& layout) {
- if (Render2D::EnableFontFallback && Render2D::FallbackFonts) {
- return GetCharPositionInternal(Render2D::FallbackFonts, text, index, layout);
- }
- else {
- return GetCharPositionInternal(text, index, layout);
- }
- }
-
- ///
- /// Calculates character position for given text and character index, follows the fallback settings defined in .
- ///
- /// The input text to test.
- /// The input text range (substring range of the input text parameter).
- /// The text position to get coordinates of.
- /// The text layout properties.
- /// The character position (upper left corner which can be used for a caret position).
- API_FUNCTION() FORCE_INLINE Float2 GetCharPosition(const StringView& text, API_PARAM(Ref) const TextRange& textRange, int32 index, API_PARAM(Ref) const TextLayoutOptions& layout)
- {
- if (Render2D::EnableFontFallback && Render2D::FallbackFonts) {
- return GetCharPositionInternal(Render2D::FallbackFonts, textRange.Substring(text), index, layout);
- }
- else {
- return GetCharPositionInternal(textRange.Substring(text), index, layout);
- }
- }
-
- ///
- /// Calculates character position for given text and character index, follows the fallback settings defined in .
+ /// Calculates character position for given text and character index
///
/// The input text to test.
/// The text position to get coordinates of.
/// The character position (upper left corner which can be used for a caret position).
API_FUNCTION() FORCE_INLINE Float2 GetCharPosition(const StringView& text, int32 index)
{
- if (Render2D::EnableFontFallback && Render2D::FallbackFonts) {
- return GetCharPositionInternal(Render2D::FallbackFonts, text, index, TextLayoutOptions());
- }
- else {
- return GetCharPositionInternal(text, index, TextLayoutOptions());
- }
+ return GetCharPosition(text, index, TextLayoutOptions());
}
///
- /// Calculates character position for given text and character index, follows the fallback settings defined in .
+ /// Calculates character position for given text and character index
///
/// The input text to test.
/// The input text range (substring range of the input text parameter).
@@ -990,12 +522,7 @@ public:
/// The character position (upper left corner which can be used for a caret position).
API_FUNCTION() FORCE_INLINE Float2 GetCharPosition(const StringView& text, API_PARAM(Ref) const TextRange& textRange, int32 index)
{
- if (Render2D::EnableFontFallback && Render2D::FallbackFonts) {
- return GetCharPositionInternal(Render2D::FallbackFonts, textRange.Substring(text), index, TextLayoutOptions());
- }
- else {
- return GetCharPositionInternal(textRange.Substring(text), index, TextLayoutOptions());
- }
+ return GetCharPosition(textRange.Substring(text), index, TextLayoutOptions());
}
///
@@ -1004,7 +531,6 @@ public:
void FlushFaceSize() const;
public:
-
// [Object]
String ToString() const override;
};
diff --git a/Source/Engine/Render2D/FontAsset.cpp b/Source/Engine/Render2D/FontAsset.cpp
index ea629367f..53fbdc930 100644
--- a/Source/Engine/Render2D/FontAsset.cpp
+++ b/Source/Engine/Render2D/FontAsset.cpp
@@ -199,25 +199,29 @@ bool FontAsset::Save(const StringView& path)
#endif
-
-///
-/// Check if the font contains the glyph of a char
-///
-/// The char to test.
-/// True if the font contains the glyph of the char, otherwise false.
-
-bool FontAsset::ContainsChar(Char c) const {
- return FT_Get_Char_Index(GetFTFace(), c) > 0;
+bool FontAsset::ContainsChar(Char c) const
+{
+ return FT_Get_Char_Index(_face, c) > 0;
}
void FontAsset::Invalidate()
{
ScopeLock lock(Locker);
-
for (auto font : _fonts)
- {
font->Invalidate();
- }
+}
+
+uint64 FontAsset::GetMemoryUsage() const
+{
+ Locker.Lock();
+ uint64 result = BinaryAsset::GetMemoryUsage();
+ result += sizeof(FontAsset) - sizeof(BinaryAsset);
+ result += sizeof(FT_FaceRec);
+ result += _fontFile.Length();
+ for (auto font : _fonts)
+ result += sizeof(Font);
+ Locker.Unlock();
+ return result;
}
bool FontAsset::init(AssetInitData& initData)
diff --git a/Source/Engine/Render2D/FontAsset.h b/Source/Engine/Render2D/FontAsset.h
index f3c909911..a93276bf1 100644
--- a/Source/Engine/Render2D/FontAsset.h
+++ b/Source/Engine/Render2D/FontAsset.h
@@ -93,6 +93,7 @@ API_CLASS(NoSpawn) class FLAXENGINE_API FontAsset : public BinaryAsset
{
DECLARE_BINARY_ASSET_HEADER(FontAsset, 3);
friend Font;
+
private:
FT_Face _face;
FontOptions _options;
@@ -175,7 +176,7 @@ public:
#endif
///
- /// Check if the font contains the glyph of a char
+ /// Check if the font contains the glyph of a char.
///
/// The char to test.
/// True if the font contains the glyph of the char, otherwise false.
@@ -186,6 +187,10 @@ public:
///
API_FUNCTION() void Invalidate();
+public:
+ // [BinaryAsset]
+ uint64 GetMemoryUsage() const override;
+
protected:
// [BinaryAsset]
bool init(AssetInitData& initData) override;
diff --git a/Source/Engine/Render2D/FontManager.cpp b/Source/Engine/Render2D/FontManager.cpp
index 5b08c1d87..2e1ba8c6b 100644
--- a/Source/Engine/Render2D/FontManager.cpp
+++ b/Source/Engine/Render2D/FontManager.cpp
@@ -27,7 +27,6 @@ using namespace FontManagerImpl;
class FontManagerService : public EngineService
{
public:
-
FontManagerService()
: EngineService(TEXT("Font Manager"), -700)
{
@@ -155,9 +154,12 @@ bool FontManager::AddNewEntry(Font* font, Char c, FontCharacterEntry& entry)
// Get the index to the glyph in the font face
const FT_UInt glyphIndex = FT_Get_Char_Index(face, c);
- if (glyphIndex == 0) {
+#if !BUILD_RELEASE
+ if (glyphIndex == 0)
+ {
LOG(Warning, "Font `{}` doesn't contain character `\\u{:x}`, consider choosing another font. ", String(face->family_name), c);
}
+#endif
// Load the glyph
const FT_Error error = FT_Load_Glyph(face, glyphIndex, glyphFlags);
@@ -287,6 +289,7 @@ bool FontManager::AddNewEntry(Font* font, Char c, FontCharacterEntry& entry)
entry.UVSize.X = static_cast(slot->Width - 2 * padding);
entry.UVSize.Y = static_cast(slot->Height - 2 * padding);
entry.Slot = slot;
+ entry.Font = font;
return false;
}
diff --git a/Source/Engine/Render2D/Render2D.cpp b/Source/Engine/Render2D/Render2D.cpp
index fa52baff0..34cb2c693 100644
--- a/Source/Engine/Render2D/Render2D.cpp
+++ b/Source/Engine/Render2D/Render2D.cpp
@@ -3,7 +3,6 @@
#include "Render2D.h"
#include "Font.h"
#include "FontManager.h"
-#include "FallbackFonts.h"
#include "FontTextureAtlas.h"
#include "RotatedRectangle.h"
#include "SpriteAtlas.h"
@@ -55,7 +54,7 @@ const bool DownsampleForBlur = false;
PACK_STRUCT(struct Data {
Matrix ViewProjection;
-});
+ });
PACK_STRUCT(struct BlurData {
Float2 InvBufferSize;
@@ -63,7 +62,7 @@ PACK_STRUCT(struct BlurData {
float Dummy0;
Float4 Bounds;
Float4 WeightAndOffsets[RENDER2D_BLUR_MAX_SAMPLES / 2];
-});
+ });
enum class DrawCallType : byte
{
@@ -181,9 +180,7 @@ struct ClipMask
Rectangle Bounds;
};
-Render2D::RenderingFeatures Render2D::Features = RenderingFeatures::VertexSnapping;
-bool Render2D::EnableFontFallback = true;
-FontFallbackList* Render2D::FallbackFonts = nullptr;
+Render2D::RenderingFeatures Render2D::Features = RenderingFeatures::VertexSnapping | RenderingFeatures::FallbackFonts;
namespace
{
@@ -197,7 +194,6 @@ namespace
// Drawing
Array DrawCalls;
Array Lines;
- Array BlockedTextLines;
Array Lines2;
bool IsScissorsRectEmpty;
bool IsScissorsRectEnabled;
@@ -1141,12 +1137,12 @@ void DrawBatch(int32 startIndex, int32 count)
}
// Draw
- Context->BindVB(ToSpan(&vb, 1)); // TODO: reduce bindings frequency
- Context->BindIB(ib); // TODO: reduce bindings frequency
+ Context->BindVB(ToSpan(&vb, 1));
+ Context->BindIB(ib);
Context->DrawIndexed(countIb, 0, d.StartIB);
}
-void Render2D::DrawTextInternal(Font* font, const StringView& text, const Color& color, const Float2& location, MaterialBase* customMaterial)
+void Render2D::DrawText(Font* font, const StringView& text, const Color& color, const Float2& location, MaterialBase* customMaterial)
{
RENDER2D_CHECK_RENDERING_STATE;
@@ -1163,6 +1159,7 @@ void Render2D::DrawTextInternal(Font* font, const StringView& text, const Color&
FontCharacterEntry previous;
int32 kerning;
float scale = 1.0f / FontManager::FontScale;
+ const bool enableFallbackFonts = EnumHasAllFlags(Features, RenderingFeatures::FallbackFonts);
// Render all characters
FontCharacterEntry entry;
@@ -1178,7 +1175,7 @@ void Render2D::DrawTextInternal(Font* font, const StringView& text, const Color&
drawCall.AsChar.Mat = nullptr;
}
Float2 pointer = location;
- for (int32 currentIndex = 0; currentIndex < text.Length(); currentIndex++)
+ for (int32 currentIndex = 0; currentIndex <= text.Length(); currentIndex++)
{
// Cache current character
const Char currentChar = text[currentIndex];
@@ -1187,7 +1184,7 @@ void Render2D::DrawTextInternal(Font* font, const StringView& text, const Color&
if (currentChar != '\n')
{
// Get character entry
- font->GetCharacter(currentChar, entry);
+ font->GetCharacter(currentChar, entry, enableFallbackFonts);
// Check if need to select/change font atlas (since characters even in the same font may be located in different atlases)
if (fontAtlas == nullptr || entry.TextureIndex != fontAtlasIndex)
@@ -1214,7 +1211,7 @@ void Render2D::DrawTextInternal(Font* font, const StringView& text, const Color&
// Get kerning
if (!isWhitespace && previous.IsValid)
{
- kerning = font->GetKerning(previous.Character, entry.Character);
+ kerning = entry.Font->GetKerning(previous.Character, entry.Character);
}
else
{
@@ -1254,12 +1251,12 @@ void Render2D::DrawTextInternal(Font* font, const StringView& text, const Color&
}
}
-void Render2D::DrawTextInternal(Font* font, const StringView& text, const TextRange& textRange, const Color& color, const Float2& location, MaterialBase* customMaterial)
+void Render2D::DrawText(Font* font, const StringView& text, const TextRange& textRange, const Color& color, const Float2& location, MaterialBase* customMaterial)
{
- DrawTextInternal(font, textRange.Substring(text), color, location, customMaterial);
+ DrawText(font, textRange.Substring(text), color, location, customMaterial);
}
-void Render2D::DrawTextInternal(Font* font, const StringView& text, const Color& color, const TextLayoutOptions& layout, MaterialBase* customMaterial)
+void Render2D::DrawText(Font* font, const StringView& text, const Color& color, const TextLayoutOptions& layout, MaterialBase* customMaterial)
{
RENDER2D_CHECK_RENDERING_STATE;
@@ -1277,6 +1274,7 @@ void Render2D::DrawTextInternal(Font* font, const StringView& text, const Color&
FontCharacterEntry previous;
int32 kerning;
float scale = layout.Scale / FontManager::FontScale;
+ const bool enableFallbackFonts = EnumHasAllFlags(Features, RenderingFeatures::FallbackFonts);
// Process text to get lines
Lines.Clear();
@@ -1303,10 +1301,14 @@ void Render2D::DrawTextInternal(Font* font, const StringView& text, const Color&
// Render all characters from the line
for (int32 charIndex = line.FirstCharIndex; charIndex <= line.LastCharIndex; charIndex++)
{
- const Char c = text[charIndex];
- if (c != '\n')
+ // Cache current character
+ const Char currentChar = text[charIndex];
+
+ // Check if it isn't a newline character
+ if (currentChar != '\n')
{
- font->GetCharacter(c, entry);
+ // Get character entry
+ font->GetCharacter(currentChar, entry, enableFallbackFonts);
// Check if need to select/change font atlas (since characters even in the same font may be located in different atlases)
if (fontAtlas == nullptr || entry.TextureIndex != fontAtlasIndex)
@@ -1328,10 +1330,10 @@ void Render2D::DrawTextInternal(Font* font, const StringView& text, const Color&
}
// Get kerning
- const bool isWhitespace = StringUtils::IsWhitespace(c);
+ const bool isWhitespace = StringUtils::IsWhitespace(currentChar);
if (!isWhitespace && previous.IsValid)
{
- kerning = font->GetKerning(previous.Character, entry.Character);
+ kerning = entry.Font->GetKerning(previous.Character, entry.Character);
}
else
{
@@ -1367,317 +1369,9 @@ void Render2D::DrawTextInternal(Font* font, const StringView& text, const Color&
}
}
-void Render2D::DrawTextInternal(Font* font, const StringView& text, const TextRange& textRange, const Color& color, const TextLayoutOptions& layout, MaterialBase* customMaterial)
+void Render2D::DrawText(Font* font, const StringView& text, const TextRange& textRange, const Color& color, const TextLayoutOptions& layout, MaterialBase* customMaterial)
{
- DrawTextInternal(font, textRange.Substring(text), color, layout, customMaterial);
-}
-
-void Render2D::DrawTextInternal(Font* font, FontFallbackList* fallbacks, const StringView& text, const Color& color, const Float2& location, MaterialBase* customMaterial)
-{
- RENDER2D_CHECK_RENDERING_STATE;
-
- // Check if there is no need to do anything
- if (font == nullptr || text.Length() < 0)
- return;
-
- // Temporary data
- const Array& fallbackFonts = fallbacks->GetFontList(font->GetSize());
- uint32 fontAtlasIndex = 0;
- FontTextureAtlas* fontAtlas = nullptr;
- Float2 invAtlasSize = Float2::One;
- FontCharacterEntry previous;
- int32 kerning;
- float scale = 1.0f / FontManager::FontScale;
-
- // Process text to get lines
- Array maxAscenders;
-
- // Render all characters
- FontCharacterEntry entry;
- Render2DDrawCall drawCall;
- if (customMaterial)
- {
- drawCall.Type = DrawCallType::DrawCharMaterial;
- drawCall.AsChar.Mat = customMaterial;
- }
- else
- {
- drawCall.Type = DrawCallType::DrawChar;
- drawCall.AsChar.Mat = nullptr;
- }
-
- int32 lineIndex = 0;
- maxAscenders.Add(0);
-
- auto getFont = [&](int32 index)->Font* {
- return index >= 0 ? fallbackFonts[index] : font;
- };
-
- // Preprocess the text to determine vertical offset of blocks
- for (int32 currentIndex = 0; currentIndex < text.Length(); currentIndex++)
- {
- const Char c = text[currentIndex];
- if (c != '\n') {
- int32 fontIndex = fallbacks->GetCharFallbackIndex(c, font);
- maxAscenders[lineIndex] = Math::Max(maxAscenders[lineIndex],
- static_cast(getFont(fontIndex)->GetAscender()));
- }
- else {
- lineIndex++;
- maxAscenders.Add(0);
- }
- }
-
- lineIndex = 0;
- // The following code cut the text into blocks, according to the font used to render
- Float2 pointer = location;
- // The starting index of the current block
- int32 startIndex = 0;
- // The index of the font used by the current block
- int32 currentFontIndex = fallbacks->GetCharFallbackIndex(text[0], font);
- // The maximum font height of the current line
- float maxHeight = 0;
- for (int32 currentIndex = 0; currentIndex < text.Length(); currentIndex++)
- {
- // Cache current character
- const Char currentChar = text[currentIndex];
- int32 nextCharIndex = currentIndex + 1;
- bool moveBlock = false;
- bool moveLine = false;
- int32 nextFontIndex = currentFontIndex;
-
- // Submit block if text ends
- if (nextCharIndex == text.Length()) {
- moveBlock = true;
- }
-
- // Check if it isn't a newline character
- if (currentChar != '\n')
- {
- // Get character entry
- if (nextCharIndex < text.Length()) {
- nextFontIndex = fallbacks->GetCharFallbackIndex(text[nextCharIndex], font);
- }
-
- if (nextFontIndex != currentFontIndex) {
- moveBlock = true;
- }
- }
- else
- {
- // Move
- moveLine = moveBlock = true;
- }
-
- if (moveBlock) {
- // Render the pending block before beginning the new block
- auto fontHeight = getFont(currentFontIndex)->GetHeight();
- maxHeight = Math::Max(maxHeight, static_cast(fontHeight));
- auto fontDescender = getFont(currentFontIndex)->GetDescender();
- for (int32 renderIndex = startIndex; renderIndex <= currentIndex; renderIndex++)
- {
- // Get character entry
- getFont(currentFontIndex)->GetCharacter(text[renderIndex], entry);
-
- // Check if need to select/change font atlas (since characters even in the same font may be located in different atlases)
- if (fontAtlas == nullptr || entry.TextureIndex != fontAtlasIndex)
- {
- // Get texture atlas that contains current character
- fontAtlasIndex = entry.TextureIndex;
- fontAtlas = FontManager::GetAtlas(fontAtlasIndex);
- if (fontAtlas)
- {
- fontAtlas->EnsureTextureCreated();
- drawCall.AsChar.Tex = fontAtlas->GetTexture();
- invAtlasSize = 1.0f / fontAtlas->GetSize();
- }
- else
- {
- drawCall.AsChar.Tex = nullptr;
- invAtlasSize = 1.0f;
- }
- }
-
- // Check if character is a whitespace
- const bool isWhitespace = StringUtils::IsWhitespace(text[renderIndex]);
-
- // Get kerning
- if (!isWhitespace && previous.IsValid)
- {
- kerning = getFont(currentFontIndex)->GetKerning(previous.Character, entry.Character);
- }
- else
- {
- kerning = 0;
- }
- pointer.X += kerning * scale;
- previous = entry;
-
- // Omit whitespace characters
- if (!isWhitespace)
- {
- // Calculate character size and atlas coordinates
- const float x = pointer.X + entry.OffsetX * scale;
- const float y = pointer.Y + (fontHeight + fontDescender - entry.OffsetY) * scale;
-
- Rectangle charRect(x, y + (maxAscenders[lineIndex] - getFont(currentFontIndex)->GetAscender()) / 2, entry.UVSize.X * scale, entry.UVSize.Y * scale);
-
- Float2 upperLeftUV = entry.UV * invAtlasSize;
- Float2 rightBottomUV = (entry.UV + entry.UVSize) * invAtlasSize;
-
- // Add draw call
- drawCall.StartIB = IBIndex;
- drawCall.CountIB = 6;
- DrawCalls.Add(drawCall);
- WriteRect(charRect, color, upperLeftUV, rightBottomUV);
- }
-
- // Move
- pointer.X += entry.AdvanceX * scale;
- }
-
- if (moveLine) {
- pointer.X = location.X;
- pointer.Y += maxHeight * scale;
- // Clear max height
- maxHeight = 0;
- lineIndex++;
- }
-
- // Start new block
- startIndex = nextCharIndex;
- currentFontIndex = nextFontIndex;
- }
- }
-}
-
-void Render2D::DrawTextInternal(Font* font, FontFallbackList* fallbacks, const StringView& text, const TextRange& textRange, const Color& color, const Float2& location, MaterialBase* customMaterial)
-{
- DrawTextInternal(font, fallbacks, textRange.Substring(text), color, location, customMaterial);
-}
-
-void Render2D::DrawTextInternal(Font* font, FontFallbackList* fallbacks, const StringView& text, const Color& color, const TextLayoutOptions& layout, MaterialBase* customMaterial)
-{
- RENDER2D_CHECK_RENDERING_STATE;
-
- // Check if there is no need to do anything
- if (font == nullptr || text.IsEmpty() || layout.Scale <= ZeroTolerance)
- return;
-
- // Temporary data
- const Array& fallbackFonts = fallbacks->GetFontList(font->GetSize());
- uint32 fontAtlasIndex = 0;
- FontTextureAtlas* fontAtlas = nullptr;
- Float2 invAtlasSize = Float2::One;
- FontCharacterEntry previous;
- int32 kerning;
- float scale = layout.Scale / FontManager::FontScale;
-
- // Process text to get lines
- BlockedTextLines.Clear();
- font->ProcessText(fallbacks, text, BlockedTextLines, layout);
-
- // Render all lines
- FontCharacterEntry entry;
- Render2DDrawCall drawCall;
- if (customMaterial)
- {
- drawCall.Type = DrawCallType::DrawCharMaterial;
- drawCall.AsChar.Mat = customMaterial;
- }
- else
- {
- drawCall.Type = DrawCallType::DrawChar;
- drawCall.AsChar.Mat = nullptr;
- }
-
- auto getFont = [&](int32 index)->Font* {
- return index >= 0 ? fallbackFonts[index] : font;
- };
-
- for (int32 lineIndex = 0; lineIndex < BlockedTextLines.Count(); lineIndex++)
- {
- const BlockedTextLineCache& line = BlockedTextLines[lineIndex];
- for (int32 blockIndex = 0; blockIndex < line.Blocks.Count(); blockIndex++)
- {
- const FontBlockCache& block = BlockedTextLines[lineIndex].Blocks[blockIndex];
- auto fontHeight = getFont(block.FallbackFontIndex)->GetHeight();
- auto fontDescender = getFont(block.FallbackFontIndex)->GetDescender();
- Float2 pointer = line.Location + block.Location;
-
- for (int32 charIndex = block.FirstCharIndex; charIndex <= block.LastCharIndex; charIndex++)
- {
- Char c = text[charIndex];
- if (c == '\n')
- {
- continue;
- }
-
- // Get character entry
- getFont(block.FallbackFontIndex)->GetCharacter(c, entry);
-
- // Check if need to select/change font atlas (since characters even in the same font may be located in different atlases)
- if (fontAtlas == nullptr || entry.TextureIndex != fontAtlasIndex)
- {
- // Get texture atlas that contains current character
- fontAtlasIndex = entry.TextureIndex;
- fontAtlas = FontManager::GetAtlas(fontAtlasIndex);
- if (fontAtlas)
- {
- fontAtlas->EnsureTextureCreated();
- invAtlasSize = 1.0f / fontAtlas->GetSize();
- drawCall.AsChar.Tex = fontAtlas->GetTexture();
- }
- else
- {
- invAtlasSize = 1.0f;
- drawCall.AsChar.Tex = nullptr;
- }
- }
-
- // Get kerning
- const bool isWhitespace = StringUtils::IsWhitespace(c);
- if (!isWhitespace && previous.IsValid)
- {
- kerning = getFont(block.FallbackFontIndex)->GetKerning(previous.Character, entry.Character);
- }
- else
- {
- kerning = 0;
- }
- pointer.X += (float)kerning * scale;
- previous = entry;
-
- // Omit whitespace characters
- if (!isWhitespace)
- {
- // Calculate character size and atlas coordinates
- const float x = pointer.X + entry.OffsetX * scale;
- const float y = pointer.Y - entry.OffsetY * scale + Math::Ceil((fontHeight + fontDescender) * scale);
-
- Rectangle charRect(x, y, entry.UVSize.X * scale, entry.UVSize.Y * scale);
- charRect.Offset(layout.Bounds.Location);
-
- Float2 upperLeftUV = entry.UV * invAtlasSize;
- Float2 rightBottomUV = (entry.UV + entry.UVSize) * invAtlasSize;
-
- // Add draw call
- drawCall.StartIB = IBIndex;
- drawCall.CountIB = 6;
- DrawCalls.Add(drawCall);
- WriteRect(charRect, color, upperLeftUV, rightBottomUV);
- }
-
- // Move
- pointer.X += entry.AdvanceX * scale;
- }
- }
- }
-}
-
-void Render2D::DrawTextInternal(Font* font, FontFallbackList* fallbacks, const StringView& text, const TextRange& textRange, const Color& color, const TextLayoutOptions& layout, MaterialBase* customMaterial)
-{
- DrawTextInternal(font, fallbacks, textRange.Substring(text), color, layout, customMaterial);
+ DrawText(font, textRange.Substring(text), color, layout, customMaterial);
}
FORCE_INLINE bool NeedAlphaWithTint(const Color& color)
@@ -2181,22 +1875,22 @@ void Render2D::DrawBezier(const Float2& p1, const Float2& p2, const Float2& p3,
{
RENDER2D_CHECK_RENDERING_STATE;
- // Find amount of blocks to use
+ // Find amount of segments to use
const Float2 d1 = p2 - p1;
const Float2 d2 = p3 - p2;
const Float2 d3 = p4 - p3;
const float len = d1.Length() + d2.Length() + d3.Length();
- const int32 blockCount = Math::Clamp(Math::CeilToInt(len * 0.05f), 1, 100);
- const float blockCountInv = 1.0f / blockCount;
+ const int32 segmentCount = Math::Clamp(Math::CeilToInt(len * 0.05f), 1, 100);
+ const float segmentCountInv = 1.0f / segmentCount;
- // Draw blocked curve
+ // Draw segmented curve
Float2 p;
AnimationUtils::Bezier(p1, p2, p3, p4, 0, p);
Lines2.Clear();
Lines2.Add(p);
- for (int32 i = 1; i <= blockCount; i++)
+ for (int32 i = 1; i <= segmentCount; i++)
{
- const float t = i * blockCountInv;
+ const float t = i * segmentCountInv;
AnimationUtils::Bezier(p1, p2, p3, p4, t, p);
Lines2.Add(p);
}
diff --git a/Source/Engine/Render2D/Render2D.cs b/Source/Engine/Render2D/Render2D.cs
index b36f155df..c4d9e81b4 100644
--- a/Source/Engine/Render2D/Render2D.cs
+++ b/Source/Engine/Render2D/Render2D.cs
@@ -1,13 +1,11 @@
// Copyright (c) 2012-2023 Wojciech Figat. All rights reserved.
-using FlaxEngine.GUI;
using System;
namespace FlaxEngine
{
partial class Render2D
{
-
///
/// Pushes transformation layer.
///
@@ -102,7 +100,7 @@ namespace FlaxEngine
}
///
- /// Draws a text, follows the font fallback settings defined in .
+ /// Draws a text.
///
/// The font to use.
/// The text to render.
@@ -128,7 +126,7 @@ namespace FlaxEngine
}
///
- /// Draws a text using a custom material shader. Given material must have GUI domain and a public parameter named Font (texture parameter used for a font atlas sampling). Follows the font fallback settings defined in .
+ /// Draws a text using a custom material shader. Given material must have GUI domain and a public parameter named Font (texture parameter used for a font atlas sampling).
///
/// The font to use.
/// Custom material for font characters rendering. It must contain texture parameter named Font used to sample font texture.
diff --git a/Source/Engine/Render2D/Render2D.h b/Source/Engine/Render2D/Render2D.h
index 6657d8542..5e5e952dc 100644
--- a/Source/Engine/Render2D/Render2D.h
+++ b/Source/Engine/Render2D/Render2D.h
@@ -15,7 +15,6 @@ struct Matrix3x3;
struct Viewport;
struct TextRange;
class Font;
-class FontFallbackList;
class GPUPipelineState;
class GPUTexture;
class GPUTextureView;
@@ -34,7 +33,7 @@ API_CLASS(Static) class FLAXENGINE_API Render2D
///
/// The rendering features and options flags.
///
- API_ENUM(Attributes = "Flags") enum class RenderingFeatures
+ API_ENUM(Attributes="Flags") enum class RenderingFeatures
{
///
/// The none.
@@ -45,6 +44,11 @@ API_CLASS(Static) class FLAXENGINE_API Render2D
/// Enables automatic geometry vertices snapping to integer coordinates in screen space. Reduces aliasing and sampling artifacts. Might be disabled for 3D projection viewport or for complex UI transformations.
///
VertexSnapping = 1,
+
+ ///
+ /// Enables automatic characters usage from fallback fonts.
+ ///
+ FallbackFonts = 2,
};
struct CustomData
@@ -54,7 +58,6 @@ API_CLASS(Static) class FLAXENGINE_API Render2D
};
public:
-
///
/// Checks if interface is during rendering phrase (Draw calls may be performed without failing).
///
@@ -70,10 +73,6 @@ public:
///
API_FIELD() static RenderingFeatures Features;
- API_FIELD() static bool EnableFontFallback;
-
- API_FIELD() static FontFallbackList* FallbackFonts;
-
///
/// Called when frame rendering begins by the graphics device.
///
@@ -180,17 +179,17 @@ public:
public:
///
- /// Draws a text, with font fallbacking disabled.
+ /// Draws a text.
///
/// The font to use.
/// The text to render.
/// The text color.
/// The text location.
/// The custom material for font characters rendering. It must contain texture parameter named Font used to sample font texture.
- API_FUNCTION() static void DrawTextInternal(Font* font, const StringView& text, const Color& color, const Float2& location, MaterialBase* customMaterial = nullptr);
+ API_FUNCTION() static void DrawText(Font* font, const StringView& text, const Color& color, const Float2& location, MaterialBase* customMaterial = nullptr);
///
- /// Draws a text, with font fallbacking disabled.
+ /// Draws a text.
///
/// The font to use.
/// The text to render.
@@ -198,20 +197,20 @@ public:
/// The text color.
/// The text location.
/// The custom material for font characters rendering. It must contain texture parameter named Font used to sample font texture.
- API_FUNCTION() static void DrawTextInternal(Font* font, const StringView& text, API_PARAM(Ref) const TextRange& textRange, const Color& color, const Float2& location, MaterialBase* customMaterial = nullptr);
+ API_FUNCTION() static void DrawText(Font* font, const StringView& text, API_PARAM(Ref) const TextRange& textRange, const Color& color, const Float2& location, MaterialBase* customMaterial = nullptr);
///
- /// Draws a text with formatting, with font fallbacking disabled.
+ /// Draws a text with formatting.
///
/// The font to use.
/// The text to render.
/// The text color.
/// The text layout properties.
/// The custom material for font characters rendering. It must contain texture parameter named Font used to sample font texture.
- API_FUNCTION() static void DrawTextInternal(Font* font, const StringView& text, const Color& color, API_PARAM(Ref) const TextLayoutOptions& layout, MaterialBase* customMaterial = nullptr);
+ API_FUNCTION() static void DrawText(Font* font, const StringView& text, const Color& color, API_PARAM(Ref) const TextLayoutOptions& layout, MaterialBase* customMaterial = nullptr);
///
- /// Draws a text with formatting, with font fallbacking disabled.
+ /// Draws a text with formatting.
///
/// The font to use.
/// The text to render.
@@ -219,120 +218,7 @@ public:
/// The text color.
/// The text layout properties.
/// The custom material for font characters rendering. It must contain texture parameter named Font used to sample font texture.
- API_FUNCTION() static void DrawTextInternal(Font* font, const StringView& text, API_PARAM(Ref) const TextRange& textRange, const Color& color, API_PARAM(Ref) const TextLayoutOptions& layout, MaterialBase* customMaterial = nullptr);
-
- ///
- /// Draws a text, using custom fallback options.
- ///
- /// The fonts to use, ordered by priority.
- /// The text to render.
- /// The input text range (substring range of the input text parameter).
- /// The text color.
- /// The text location.
- /// The custom material for font characters rendering. It must contain texture parameter named Font used to sample font texture.
- API_FUNCTION() static void DrawTextInternal(Font* font, FontFallbackList* fallbacks, const StringView& text, const Color& color, const Float2& location, MaterialBase* customMaterial = nullptr);
-
- ///
- /// Draws a text with formatting, using custom fallback options.
- ///
- /// The fonts to use, ordered by priority.
- /// The text to render.
- /// The text color.
- /// The text layout properties.
- /// The custom material for font characters rendering. It must contain texture parameter named Font used to sample font texture.
- API_FUNCTION() static void DrawTextInternal(Font* font, FontFallbackList* fallbacks, const StringView& text, API_PARAM(Ref) const TextRange& textRange, const Color& color, const Float2& location, MaterialBase* customMaterial = nullptr);
-
- ///
- /// Draws a text with formatting, using custom fallback options.
- ///
- /// The fonts to use, ordered by priority.
- /// The text to render.
- /// The input text range (substring range of the input text parameter).
- /// The text color.
- /// The text layout properties.
- /// The custom material for font characters rendering. It must contain texture parameter named Font used to sample font texture.
- API_FUNCTION() static void DrawTextInternal(Font* font, FontFallbackList* fallbacks, const StringView& text, const Color& color, API_PARAM(Ref) const TextLayoutOptions& layout, MaterialBase* customMaterial = nullptr);
-
- ///
- /// Draws a text with formatting, using custom fallback options.
- ///
- /// The fonts to use, ordered by priority.
- /// The text to render.
- /// The input text range (substring range of the input text parameter).
- /// The text color.
- /// The text layout properties.
- /// The custom material for font characters rendering. It must contain texture parameter named Font used to sample font texture.
- API_FUNCTION() static void DrawTextInternal(Font* font, FontFallbackList* fallbacks, const StringView& text, API_PARAM(Ref) const TextRange& textRange, const Color& color, API_PARAM(Ref) const TextLayoutOptions& layout, MaterialBase* customMaterial = nullptr);
-
- ///
- /// Draws a text, follows the fallback settings defined in .
- ///
- /// The font to use.
- /// The text to render.
- /// The text color.
- /// The text location.
- /// The custom material for font characters rendering. It must contain texture parameter named Font used to sample font texture.
- API_FUNCTION() FORCE_INLINE static void DrawText(Font* font, const StringView& text, const Color& color, const Float2& location, MaterialBase* customMaterial = nullptr) {
- if (EnableFontFallback && FallbackFonts) {
- DrawTextInternal(font, FallbackFonts, text, color, location, customMaterial);
- }
- else {
- DrawTextInternal(font, text, color, location, customMaterial);
- }
- }
-
- ///
- /// Draws a text, follows the fallback settings defined in .
- ///
- /// The font to use.
- /// The text to render.
- /// The input text range (substring range of the input text parameter).
- /// The text color.
- /// The text location.
- /// The custom material for font characters rendering. It must contain texture parameter named Font used to sample font texture.
- API_FUNCTION() FORCE_INLINE static void DrawText(Font* font, const StringView& text, API_PARAM(Ref) const TextRange& textRange, const Color& color, const Float2& location, MaterialBase* customMaterial = nullptr) {
- if (EnableFontFallback && FallbackFonts) {
- DrawTextInternal(font, FallbackFonts, text, textRange, color, location, customMaterial);
- }
- else {
- DrawTextInternal(font, text, textRange, color, location, customMaterial);
- }
- }
-
- ///
- /// Draws a text with formatting, follows the fallback settings defined in .
- ///
- /// The font to use.
- /// The text to render.
- /// The text color.
- /// The text layout properties.
- /// The custom material for font characters rendering. It must contain texture parameter named Font used to sample font texture.
- API_FUNCTION() FORCE_INLINE static void DrawText(Font* font, const StringView& text, const Color& color, API_PARAM(Ref) const TextLayoutOptions& layout, MaterialBase* customMaterial = nullptr) {
- if (EnableFontFallback && FallbackFonts) {
- DrawTextInternal(font, FallbackFonts, text, color, layout, customMaterial);
- }
- else {
- DrawTextInternal(font, text, color, layout, customMaterial);
- }
- }
-
- ///
- /// Draws a text with formatting, follows the fallback settings defined in .
- ///
- /// The font to use.
- /// The text to render.
- /// The input text range (substring range of the input text parameter).
- /// The text color.
- /// The text layout properties.
- /// The custom material for font characters rendering. It must contain texture parameter named Font used to sample font texture.
- API_FUNCTION() FORCE_INLINE static void DrawText(Font* font, const StringView& text, API_PARAM(Ref) const TextRange& textRange, const Color& color, API_PARAM(Ref) const TextLayoutOptions& layout, MaterialBase* customMaterial = nullptr) {
- if (EnableFontFallback && FallbackFonts) {
- DrawTextInternal(font, FallbackFonts, text, textRange, color, layout, customMaterial);
- }
- else {
- DrawTextInternal(font, text, textRange, color, layout, customMaterial);
- }
- }
+ API_FUNCTION() static void DrawText(Font* font, const StringView& text, API_PARAM(Ref) const TextRange& textRange, const Color& color, API_PARAM(Ref) const TextLayoutOptions& layout, MaterialBase* customMaterial = nullptr);
///
/// Fills a rectangle area.
@@ -571,3 +457,5 @@ public:
/// The color.
API_FUNCTION() static void FillTriangle(const Float2& p0, const Float2& p1, const Float2& p2, const Color& color);
};
+
+DECLARE_ENUM_OPERATORS(Render2D::RenderingFeatures);
diff --git a/Source/Engine/Scripting/Scripting.cs b/Source/Engine/Scripting/Scripting.cs
index a4cfd76b1..188333ff1 100644
--- a/Source/Engine/Scripting/Scripting.cs
+++ b/Source/Engine/Scripting/Scripting.cs
@@ -294,12 +294,14 @@ namespace FlaxEngine
style.DragWindow = style.BackgroundSelected * 0.7f;
// Use optionally bundled default font (matches Editor)
- FontAsset defaultFont = Content.LoadAsyncInternal("Editor/Fonts/Roboto-Regular");
-
- style.FontTitle = new FontReference(defaultFont, 18).GetFont();
- style.FontLarge = new FontReference(defaultFont, 14).GetFont();
- style.FontMedium = new FontReference(defaultFont, 9).GetFont();
- style.FontSmall = new FontReference(defaultFont, 9).GetFont();
+ var defaultFont = Content.LoadAsyncInternal("Editor/Fonts/Roboto-Regular");
+ if (defaultFont)
+ {
+ style.FontTitle = defaultFont.CreateFont(18);
+ style.FontLarge = defaultFont.CreateFont(14);
+ style.FontMedium = defaultFont.CreateFont(9);
+ style.FontSmall = defaultFont.CreateFont(9);
+ }
Style.Current = style;
}
diff --git a/Source/Engine/UI/GUI/Common/Label.cs b/Source/Engine/UI/GUI/Common/Label.cs
index 8de54fda3..3c7c04fb2 100644
--- a/Source/Engine/UI/GUI/Common/Label.cs
+++ b/Source/Engine/UI/GUI/Common/Label.cs
@@ -182,12 +182,6 @@ namespace FlaxEngine.GUI
set => _autoFitTextRange = value;
}
- ///
- /// Gets or sets whether to fallback when the primary font cannot render a char.
- ///
- [EditorOrder(120), DefaultValue(true), Tooltip("Whether to fallback when the font cannot render a char.")]
- public bool EnableFontFallback { get; set; } = true;
-
///
/// Initializes a new instance of the class.
///
@@ -239,23 +233,7 @@ namespace FlaxEngine.GUI
}
}
- if (EnableFontFallback)
- {
- Render2D.DrawText(_font.GetFont(), Material, _text, rect, color, hAlignment, wAlignment, Wrapping, BaseLinesGapScale, scale);
- }
- else
- {
- var layout = new TextLayoutOptions
- {
- Bounds = rect,
- HorizontalAlignment = hAlignment,
- VerticalAlignment = wAlignment,
- TextWrapping = Wrapping,
- Scale = scale,
- BaseLinesGapScale = BaseLinesGapScale,
- };
- Render2D.DrawTextInternal(_font.GetFont(), _text, color, ref layout, Material);
- }
+ Render2D.DrawText(_font.GetFont(), Material, _text, rect, color, hAlignment, wAlignment, Wrapping, BaseLinesGapScale, scale);
if (ClipText)
Render2D.PopClip();
@@ -276,8 +254,7 @@ namespace FlaxEngine.GUI
layout.Bounds.Size.X = Width - Margin.Width;
else if (_autoWidth && !_autoHeight)
layout.Bounds.Size.Y = Height - Margin.Height;
- _textSize = EnableFontFallback ?
- font.MeasureText(_text, ref layout) : font.MeasureTextInternal(_text, ref layout);
+ _textSize = font.MeasureText(_text, ref layout);
_textSize.Y *= BaseLinesGapScale;
// Check if size is controlled via text
diff --git a/Source/Engine/UI/GUI/Common/RichTextBox.Parsing.cs b/Source/Engine/UI/GUI/Common/RichTextBox.Parsing.cs
index ab01df12b..2270136ae 100644
--- a/Source/Engine/UI/GUI/Common/RichTextBox.Parsing.cs
+++ b/Source/Engine/UI/GUI/Common/RichTextBox.Parsing.cs
@@ -1,6 +1,5 @@
// Copyright (c) 2012-2023 Wojciech Figat. All rights reserved.
-using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using FlaxEngine.Utilities;
diff --git a/Source/Engine/UI/GUI/Common/RichTextBox.Tags.cs b/Source/Engine/UI/GUI/Common/RichTextBox.Tags.cs
index df8e0be7c..b4351da75 100644
--- a/Source/Engine/UI/GUI/Common/RichTextBox.Tags.cs
+++ b/Source/Engine/UI/GUI/Common/RichTextBox.Tags.cs
@@ -213,18 +213,18 @@ namespace FlaxEngine.GUI
style.Alignment &= ~TextBlockStyle.Alignments.VerticalMask;
switch (valign)
{
- case "top":
- style.Alignment = TextBlockStyle.Alignments.Top;
- break;
- case "bottom":
- style.Alignment = TextBlockStyle.Alignments.Bottom;
- break;
- case "middle":
- style.Alignment = TextBlockStyle.Alignments.Middle;
- break;
- case "baseline":
- style.Alignment = TextBlockStyle.Alignments.Baseline;
- break;
+ case "top":
+ style.Alignment = TextBlockStyle.Alignments.Top;
+ break;
+ case "bottom":
+ style.Alignment = TextBlockStyle.Alignments.Bottom;
+ break;
+ case "middle":
+ style.Alignment = TextBlockStyle.Alignments.Middle;
+ break;
+ case "baseline":
+ style.Alignment = TextBlockStyle.Alignments.Baseline;
+ break;
}
}
context.StyleStack.Push(style);
@@ -245,15 +245,15 @@ namespace FlaxEngine.GUI
style.Alignment &= ~TextBlockStyle.Alignments.VerticalMask;
switch (valign)
{
- case "left":
- style.Alignment = TextBlockStyle.Alignments.Left;
- break;
- case "right":
- style.Alignment = TextBlockStyle.Alignments.Right;
- break;
- case "center":
- style.Alignment = TextBlockStyle.Alignments.Center;
- break;
+ case "left":
+ style.Alignment = TextBlockStyle.Alignments.Left;
+ break;
+ case "right":
+ style.Alignment = TextBlockStyle.Alignments.Right;
+ break;
+ case "center":
+ style.Alignment = TextBlockStyle.Alignments.Center;
+ break;
}
}
context.StyleStack.Push(style);
diff --git a/Source/Engine/UI/GUI/Common/RichTextBoxBase.cs b/Source/Engine/UI/GUI/Common/RichTextBoxBase.cs
index 46f0fb1ad..438a7e3d8 100644
--- a/Source/Engine/UI/GUI/Common/RichTextBoxBase.cs
+++ b/Source/Engine/UI/GUI/Common/RichTextBoxBase.cs
@@ -316,7 +316,6 @@ namespace FlaxEngine.GUI
color = textBlock.Style.ShadowColor;
if (!enabled)
color *= 0.6f;
- // We don't need font fallbacks for rich text since the font is user-selected
Render2D.DrawText(font, _text, ref textBlock.Range, color, textBlock.Bounds.Location + textBlock.Style.ShadowOffset, textBlock.Style.CustomMaterial);
}
diff --git a/Source/Engine/UI/GUI/Common/TextBox.cs b/Source/Engine/UI/GUI/Common/TextBox.cs
index 53266a1b2..ee4f744a6 100644
--- a/Source/Engine/UI/GUI/Common/TextBox.cs
+++ b/Source/Engine/UI/GUI/Common/TextBox.cs
@@ -1,8 +1,5 @@
// Copyright (c) 2012-2023 Wojciech Figat. All rights reserved.
-
-using System.ComponentModel;
-
namespace FlaxEngine.GUI
{
///
@@ -67,12 +64,6 @@ namespace FlaxEngine.GUI
[EditorDisplay("Text Style"), EditorOrder(2022), Tooltip("The color of the selection (Transparent if not used).")]
public Color SelectionColor { get; set; }
- ///
- /// Gets or sets whether to fallback when the primary font cannot render a char.
- ///
- [EditorOrder(120), DefaultValue(true), Tooltip("Whether to fallback when the font cannot render a char.")]
- public bool EnableFontFallback { get; set; } = true;
-
///
/// Initializes a new instance of the class.
///
@@ -112,8 +103,7 @@ namespace FlaxEngine.GUI
return Float2.Zero;
}
- return EnableFontFallback ? font.MeasureText(_text, ref _layout) :
- font.MeasureTextInternal(_text, ref _layout);
+ return font.MeasureText(_text, ref _layout);
}
///
@@ -126,9 +116,8 @@ namespace FlaxEngine.GUI
return Float2.Zero;
}
- height = (EnableFontFallback ? font.GetMaxHeight() : font.Height) / DpiScale;
- return EnableFontFallback ? font.GetCharPosition(_text, index, ref _layout) :
- font.GetCharPositionInternal(_text, index, ref _layout);
+ height = font.Height / DpiScale;
+ return font.GetCharPosition(_text, index, ref _layout);
}
///
@@ -140,8 +129,7 @@ namespace FlaxEngine.GUI
return 0;
}
- return EnableFontFallback ? font.HitTestText(_text, location, ref _layout) :
- font.HitTestTextInternal(_text, location, ref _layout);
+ return font.HitTestText(_text, location, ref _layout);
}
///
@@ -180,13 +168,9 @@ namespace FlaxEngine.GUI
// Check if sth is selected to draw selection
if (HasSelection)
{
- var leftEdge = EnableFontFallback ?
- font.GetCharPosition(_text, SelectionLeft, ref _layout) :
- font.GetCharPositionInternal(_text, SelectionLeft, ref _layout);
- var rightEdge = EnableFontFallback ?
- font.GetCharPosition(_text, SelectionRight, ref _layout) :
- font.GetCharPositionInternal(_text, SelectionRight, ref _layout);
- float fontHeight = font.GetMaxHeight() / DpiScale;
+ var leftEdge = font.GetCharPosition(_text, SelectionLeft, ref _layout);
+ var rightEdge = font.GetCharPosition(_text, SelectionRight, ref _layout);
+ float fontHeight = font.Height / DpiScale;
// Draw selection background
float alpha = Mathf.Min(1.0f, Mathf.Cos(_animateTime * BackgroundSelectedFlashSpeed) * 0.5f + 1.3f);
@@ -226,19 +210,11 @@ namespace FlaxEngine.GUI
var color = TextColor;
if (!enabled)
color *= 0.6f;
- if (EnableFontFallback)
- Render2D.DrawText(font, _text, color, ref _layout, TextMaterial);
- else
- // Draw without fallback
- Render2D.DrawTextInternal(font, _text, color, ref _layout, TextMaterial);
+ Render2D.DrawText(font, _text, color, ref _layout, TextMaterial);
}
else if (!string.IsNullOrEmpty(_watermarkText) && !IsFocused)
{
- if (EnableFontFallback)
- Render2D.DrawText(font, _watermarkText, WatermarkTextColor, ref _layout, TextMaterial);
- else
- // Draw without fallback
- Render2D.DrawTextInternal(font, _watermarkText, WatermarkTextColor, ref _layout, TextMaterial);
+ Render2D.DrawText(font, _watermarkText, WatermarkTextColor, ref _layout, TextMaterial);
}
// Caret
diff --git a/Source/Engine/UI/GUI/Common/TextBoxBase.cs b/Source/Engine/UI/GUI/Common/TextBoxBase.cs
index 55b58634d..35819da79 100644
--- a/Source/Engine/UI/GUI/Common/TextBoxBase.cs
+++ b/Source/Engine/UI/GUI/Common/TextBoxBase.cs
@@ -280,13 +280,13 @@ namespace FlaxEngine.GUI
///
[EditorDisplay("Border Style"), EditorOrder(2010), Tooltip("Whether to have a border."), ExpandGroups]
public bool HasBorder { get; set; } = true;
-
+
///
/// Gets or sets the border thickness.
///
[EditorDisplay("Border Style"), EditorOrder(2011), Tooltip("The thickness of the border."), Limit(0)]
public float BorderThickness { get; set; } = 1.0f;
-
+
///
/// Gets or sets the color of the border (Transparent if not used).
///
diff --git a/Source/Engine/UI/TextRender.cpp b/Source/Engine/UI/TextRender.cpp
index aa49dac45..d190f1123 100644
--- a/Source/Engine/UI/TextRender.cpp
+++ b/Source/Engine/UI/TextRender.cpp
@@ -239,7 +239,7 @@ void TextRender::UpdateLayout()
const bool isWhitespace = StringUtils::IsWhitespace(c);
if (!isWhitespace && previous.IsValid)
{
- kerning = font->GetKerning(previous.Character, entry.Character);
+ kerning = entry.Font->GetKerning(previous.Character, entry.Character);
}
else
{