Răsfoiți Sursa

Allow to force FreeType autohinting (old 2.3 version behavior.) Reload font faces when global font settings changed.

Lasse Öörni 12 ani în urmă
părinte
comite
840d50ce0d

+ 3 - 0
Docs/LuaScriptAPI.dox

@@ -4890,6 +4890,7 @@ Methods:
 - void SetNonFocusedMouseWheel(bool nonFocusedMouseWheel)
 - void SetUseSystemClipBoard(bool enable)
 - void SetUseMutableGlyphs(bool enable)
+- void SetForceAutoHint(bool enable)
 - UIElement* GetRoot() const
 - UIElement* GetRootModalElement() const
 - Cursor* GetCursor() const
@@ -4904,6 +4905,7 @@ Methods:
 - bool IsNonFocusedMouseWheel() const
 - bool GetUseSystemClipBoard() const
 - bool GetUseMutableGlyphs() const
+- bool GetForceAutoHint() const
 - bool HasModalElement() const
 
 Properties:
@@ -4920,6 +4922,7 @@ Properties:
 - bool nonFocusedMouseWheel
 - bool useSystemClipBoard
 - bool useMutableGlyphs
+- bool forceAutoHint
 - bool modalElement (readonly)
 
 ### UIElement : Serializable

+ 1 - 0
Docs/ScriptAPI.dox

@@ -6472,6 +6472,7 @@ Properties:
 - bool nonFocusedMouseWheel
 - bool useSystemClipBoard
 - bool useMutableGlyphs
+- bool forceAutoHint
 
 
 ### Controls

+ 1 - 1
Source/Engine/Graphics/Renderer.cpp

@@ -1509,7 +1509,7 @@ void Renderer::ResetViews()
 
 void Renderer::LoadShaders()
 {
-    LOGINFO("Reloading shaders");
+    LOGDEBUG("Reloading shaders");
     
     // Release old material shaders, mark them for reload
     ReleaseMaterialShaders();

+ 2 - 0
Source/Engine/Script/UIAPI.cpp

@@ -611,6 +611,8 @@ static void RegisterUI(asIScriptEngine* engine)
     engine->RegisterObjectMethod("UI", "bool get_useSystemClipBoard() const", asMETHOD(UI, GetUseSystemClipBoard), asCALL_THISCALL);
     engine->RegisterObjectMethod("UI", "void set_useMutableGlyphs(bool)", asMETHOD(UI, SetUseMutableGlyphs), asCALL_THISCALL);
     engine->RegisterObjectMethod("UI", "bool get_useMutableGlyphs() const", asMETHOD(UI, GetUseMutableGlyphs), asCALL_THISCALL);
+    engine->RegisterObjectMethod("UI", "void set_forceAutoHint(bool)", asMETHOD(UI, SetForceAutoHint), asCALL_THISCALL);
+    engine->RegisterObjectMethod("UI", "bool get_forceAutoHint() const", asMETHOD(UI, GetForceAutoHint), asCALL_THISCALL);
     engine->RegisterGlobalFunction("UI@+ get_ui()", asFUNCTION(GetUI), asCALL_CDECL);
 }
 

+ 21 - 11
Source/Engine/UI/Font.cpp

@@ -121,7 +121,7 @@ const FontGlyph* FontFace::GetGlyph(unsigned c)
     if (i != glyphMapping_.End())
     {
         FontGlyph& glyph = glyphs_[i->second_];
-        // Render glyph if not yet resident in a page texture
+        // Render glyph if not yet resident in a page texture (FreeType mode only)
         if (glyph.page_ == M_MAX_UNSIGNED)
             RenderGlyph(i->second_);
         // If mutable glyphs in use, move to the front of the list
@@ -218,9 +218,11 @@ bool FontFace::RenderAllGlyphs(int maxWidth, int maxHeight)
     unsigned char* imageData = image->GetData();
     memset(imageData, 0, image->GetWidth() * image->GetHeight());
     
+    int loadMode = font_->GetSubsystem<UI>()->GetForceAutoHint() ? FT_LOAD_FORCE_AUTOHINT : FT_LOAD_DEFAULT;
+
     // Render glyphs
     for (unsigned i = 0; i < glyphs_.Size(); ++i)
-        RenderGlyphBitmap(i, imageData + glyphs_[i].y_ * image->GetWidth() + glyphs_[i].x_, image->GetWidth());
+        RenderGlyphBitmap(i, imageData + glyphs_[i].y_ * image->GetWidth() + glyphs_[i].x_, image->GetWidth(), loadMode);
     
     // Load image into a texture, increment memory usage of the parent font
     SharedPtr<Texture2D> texture = font_->LoadFaceTexture(image);
@@ -254,6 +256,8 @@ void FontFace::RenderGlyph(unsigned index)
         return;
     }
     
+    int loadMode = font_->GetSubsystem<UI>()->GetForceAutoHint() ? FT_LOAD_FORCE_AUTOHINT : FT_LOAD_DEFAULT;
+
     if (!mutableGlyphs_.Size())
     {
         // Not using mutable glyphs: try to allocate from current page, reserve next page if fails
@@ -275,7 +279,7 @@ void FontFace::RenderGlyph(unsigned index)
             bitmap_ = new unsigned char[bitmapSize_];
         }
         
-        RenderGlyphBitmap(index, bitmap_.Get(), glyph.width_);
+        RenderGlyphBitmap(index, bitmap_.Get(), glyph.width_, loadMode);
         textures_.Back()->SetData(0, glyph.x_, glyph.y_, glyph.width_, glyph.height_, bitmap_.Get());
     }
     else
@@ -299,12 +303,12 @@ void FontFace::RenderGlyph(unsigned index)
         
         // Clear the cell bitmap before rendering to ensure padding
         memset(bitmap_.Get(), 0, cellWidth_ * cellHeight_);
-        RenderGlyphBitmap(index, bitmap_.Get(), cellWidth_);
+        RenderGlyphBitmap(index, bitmap_.Get(), cellWidth_, loadMode);
         textures_[0]->SetData(0, glyph.x_, glyph.y_, cellWidth_, cellHeight_, bitmap_.Get());
     }
 }
 
-void FontFace::RenderGlyphBitmap(unsigned index, unsigned char* dest, unsigned pitch)
+void FontFace::RenderGlyphBitmap(unsigned index, unsigned char* dest, unsigned pitch, int loadMode)
 {
     const FontGlyph& glyph = glyphs_[index];
     if (!glyph.width_ || !glyph.height_)
@@ -312,7 +316,7 @@ void FontFace::RenderGlyphBitmap(unsigned index, unsigned char* dest, unsigned p
     
     FT_Face face = (FT_Face)face_;
     FT_GlyphSlot slot = face->glyph;
-    FT_Load_Glyph(face, index, FT_LOAD_DEFAULT);
+    FT_Load_Glyph(face, index, loadMode);
     FT_Render_Glyph(slot, FT_RENDER_MODE_NORMAL);
 
     if (slot->bitmap.pixel_mode == FT_PIXEL_MODE_MONO)
@@ -390,7 +394,7 @@ Font::Font(Context* context) :
 Font::~Font()
 {
     // To ensure FreeType deallocates properly, first clear all faces, then release the raw font data
-    faces_.Clear();
+    ReleaseFaces();
     fontData_.Reset();
 }
 
@@ -563,7 +567,7 @@ FontFace* Font::GetFace(int pointSize)
     switch (fontType_)
     {
     case FONT_FREETYPE:
-        return GetFaceTTF(pointSize);
+        return GetFaceFreeType(pointSize);
 
     case FONT_BITMAP:
         return GetFaceBitmap(pointSize);
@@ -573,6 +577,11 @@ FontFace* Font::GetFace(int pointSize)
     }
 }
 
+void Font::ReleaseFaces()
+{
+    faces_.Clear();
+}
+
 SharedPtr<Texture2D> Font::CreateFaceTexture()
 {
     SharedPtr<Texture2D> texture(new Texture2D(context_));
@@ -595,7 +604,7 @@ SharedPtr<Texture2D> Font::LoadFaceTexture(SharedPtr<Image> image)
     return texture;
 }
 
-FontFace* Font::GetFaceTTF(int pointSize)
+FontFace* Font::GetFaceFreeType(int pointSize)
 {
     // Create & initialize FreeType library if it does not exist yet
     FreeTypeLibrary* freeType = GetSubsystem<FreeTypeLibrary>();
@@ -658,6 +667,7 @@ FontFace* Font::GetFaceTTF(int pointSize)
     // Load each of the glyphs to see the sizes & store other information
     int maxWidth = 0;
     int maxHeight = 0;
+    int loadMode = GetSubsystem<UI>()->GetForceAutoHint() ? FT_LOAD_FORCE_AUTOHINT : FT_LOAD_DEFAULT;
     FT_Pos ascender = face->size->metrics.ascender;
     
     newFace->glyphs_.Reserve(numGlyphs);
@@ -666,7 +676,7 @@ FontFace* Font::GetFaceTTF(int pointSize)
     {
         FontGlyph newGlyph;
         
-        error = FT_Load_Glyph(face, i, FT_LOAD_DEFAULT);
+        error = FT_Load_Glyph(face, i, loadMode);
         if (!error)
         {
             // Note: position within texture will be filled later
@@ -759,7 +769,7 @@ FontFace* Font::GetFaceBitmap(int pointSize)
     XMLElement infoElem = root.GetChild("info");
     if (!infoElem.IsNull())
         newFace->pointSize_ = infoElem.GetInt("size");
-        
+    
     XMLElement commonElem = root.GetChild("common");
     newFace->rowHeight_ = commonElem.GetInt("lineHeight");
     unsigned pages = commonElem.GetInt("pages");

+ 5 - 3
Source/Engine/UI/Font.h

@@ -122,7 +122,7 @@ private:
     /// Render one glyph on demand into the current texture.
     void RenderGlyph(unsigned index);
     /// Render a glyph bitmap into a memory buffer.
-    void RenderGlyphBitmap(unsigned index, unsigned char* dest, unsigned pitch);
+    void RenderGlyphBitmap(unsigned index, unsigned char* dest, unsigned pitch, int loadMode);
     /// Setup next texture for dynamic glyph rendering.
     void SetupNextTexture(int width, int height);
     /// Setup mutable glyph rendering, in which glyphs form a regular-sized grid.
@@ -177,14 +177,16 @@ public:
     /// Return font face. Pack and render to a texture if not rendered yet. Return null on error.
     FontFace* GetFace(int pointSize);
     
+    /// Release font faces and recreate them next time when requested. Called when font textures lost or global font properties change.
+    void ReleaseFaces();
     /// Create a texture for font rendering.
     SharedPtr<Texture2D> CreateFaceTexture();
     /// Load font face texture from image resource.
     SharedPtr<Texture2D> LoadFaceTexture(SharedPtr<Image> image);
     
 private:
-    /// Return True-type font face. Called internally. Return null on error.
-    FontFace* GetFaceTTF(int pointSize);
+    /// Return font face using FreeTyp. Called internally. Return null on error.
+    FontFace* GetFaceFreeType(int pointSize);
     /// Return bitmap font face. Called internally. Return null on error.
     FontFace* GetFaceBitmap(int pointSize);
     /// Convert graphics format to number of components.

+ 33 - 2
Source/Engine/UI/UI.cpp

@@ -38,6 +38,7 @@
 #include "Matrix3x4.h"
 #include "Profiler.h"
 #include "Renderer.h"
+#include "ResourceCache.h"
 #include "ScrollBar.h"
 #include "Shader.h"
 #include "ShaderVariation.h"
@@ -472,7 +473,13 @@ void UI::SetDoubleClickInterval(float interval)
 void UI::SetMaxFontTextureSize(int size)
 {
     if (IsPowerOfTwo(size) && size >= FONT_TEXTURE_MIN_SIZE)
-        maxFontTextureSize_ = size;
+    {
+        if (size != maxFontTextureSize_)
+        {
+            maxFontTextureSize_ = size;
+            ReleaseFontFaces();
+        }
+    }
 }
 
 void UI::SetNonFocusedMouseWheel(bool nonFocusedMouseWheel)
@@ -487,7 +494,20 @@ void UI::SetUseSystemClipBoard(bool enable)
 
 void UI::SetUseMutableGlyphs(bool enable)
 {
-    useMutableGlyphs_ = enable;
+    if (enable != useMutableGlyphs_)
+    {
+        useMutableGlyphs_ = enable;
+        ReleaseFontFaces();
+    }
+}
+
+void UI::SetForceAutoHint(bool enable)
+{
+    if (enable != forceAutoHint_)
+    {
+        forceAutoHint_ = enable;
+        ReleaseFontFaces();
+    }
 }
 
 IntVector2 UI::GetCursorPosition() const
@@ -832,6 +852,17 @@ void UI::SetCursorShape(CursorShape shape)
         cursor_->SetShape(shape);
 }
 
+void UI::ReleaseFontFaces()
+{
+    LOGDEBUG("Reloading font faces");
+
+    PODVector<Font*> fonts;
+    GetSubsystem<ResourceCache>()->GetResources<Font>(fonts);
+
+    for (unsigned i = 0; i < fonts.Size(); ++i)
+        fonts[i]->ReleaseFaces();
+}
+
 void UI::ProcessClickBegin(const IntVector2& cursorPos, int button, int buttons, int qualifiers, Cursor* cursor, bool cursorVisible)
 {
     if (cursorVisible)

+ 9 - 1
Source/Engine/UI/UI.h

@@ -87,6 +87,8 @@ public:
     void SetUseSystemClipBoard(bool enable);
     /// Set whether to use mutable (eraseable) glyphs to ensure a font face never expands to more than one texture. Default false.
     void SetUseMutableGlyphs(bool enable);
+    /// Set whether to force font autohinting instead of using FreeType's TTF bytecode interpreter.
+    void SetForceAutoHint(bool enable);
     
     /// Return root UI element.
     UIElement* GetRoot() const { return rootElement_; }
@@ -116,11 +118,13 @@ public:
     bool GetUseSystemClipBoard() const { return useSystemClipBoard_; }
     /// Return whether is using mutable (eraseable) glyphs for fonts.
     bool GetUseMutableGlyphs() const { return useMutableGlyphs_; }
+    /// Return whether is using forced autohinting.
+    bool GetForceAutoHint() const { return forceAutoHint_; }
     /// Return true when UI has modal element(s).
     bool HasModalElement() const;
 
 private:
-    /// Initialize when screen mode initially se.
+    /// Initialize when screen mode initially set.
     void Initialize();
     /// Update UI element logic recursively.
     void Update(float timeStep, UIElement* element);
@@ -138,6 +142,8 @@ private:
     void GetCursorPositionAndVisible(IntVector2& pos, bool& visible);
     /// Set active cursor's shape.
     void SetCursorShape(CursorShape shape);
+    /// Force release of font faces when global font properties change.
+    void ReleaseFontFaces();
     /// Handle button or touch begin.
     void ProcessClickBegin(const IntVector2& cursorPos, int button, int buttons, int qualifiers, Cursor* cursor, bool cursorVisible);
     /// Handle button or touch end.
@@ -231,6 +237,8 @@ private:
     bool useSystemClipBoard_;
     /// Flag for using mutable (eraseable) font glyphs.
     bool useMutableGlyphs_;
+    /// Flag for forcing FreeType autohinting.
+    bool forceAutoHint_;
     /// Non-modal batch size (used internally for rendering).
     unsigned nonModalBatchSize_;
     /// Timer used to trigger double click.

+ 3 - 0
Source/Extras/LuaScript/pkgs/UI/UI.pkg

@@ -19,6 +19,7 @@ class UI : public Object
     void SetNonFocusedMouseWheel(bool nonFocusedMouseWheel);
     void SetUseSystemClipBoard(bool enable);
     void SetUseMutableGlyphs(bool enable);
+    void SetForceAutoHint(bool enable);
 
     UIElement* GetRoot() const;
     UIElement* GetRootModalElement() const;
@@ -36,6 +37,7 @@ class UI : public Object
     bool IsNonFocusedMouseWheel() const;
     bool GetUseSystemClipBoard() const;
     bool GetUseMutableGlyphs() const;
+    bool GetForceAutoHint() const;
     bool HasModalElement() const;
 
     tolua_readonly tolua_property__get_set UIElement* root;
@@ -50,5 +52,6 @@ class UI : public Object
     tolua_property__is_set bool nonFocusedMouseWheel;
     tolua_property__get_set bool useSystemClipBoard;
     tolua_property__get_set bool useMutableGlyphs;
+    tolua_property__get_set bool forceAutoHint;
     tolua_readonly tolua_property__has_set bool modalElement;
 };