Browse Source

Simplify font class.

Aster@中国上海 11 years ago
parent
commit
387c89b857

+ 12 - 26
Source/Engine/UI/FontFace.cpp

@@ -33,11 +33,6 @@
 namespace Urho3D
 namespace Urho3D
 {
 {
 
 
-MutableGlyph::MutableGlyph() :
-    glyphIndex_(M_MAX_UNSIGNED)
-{
-}
-
 FontGlyph::FontGlyph() :
 FontGlyph::FontGlyph() :
     used_(false),
     used_(false),
     page_(M_MAX_UNSIGNED)
     page_(M_MAX_UNSIGNED)
@@ -45,8 +40,7 @@ FontGlyph::FontGlyph() :
 }
 }
 
 
 FontFace::FontFace(Font* font) :
 FontFace::FontFace(Font* font) :
-    font_(font),
-    hasKerning_(false)
+    font_(font)
 {
 {
 }
 }
 
 
@@ -64,10 +58,10 @@ FontFace::~FontFace()
 
 
 const FontGlyph* FontFace::GetGlyph(unsigned c)
 const FontGlyph* FontFace::GetGlyph(unsigned c)
 {
 {
-    HashMap<unsigned, unsigned>::ConstIterator i = glyphMapping_.Find(c);
+    HashMap<unsigned, FontGlyph>::Iterator i = glyphMapping_.Find(c);
     if (i != glyphMapping_.End())
     if (i != glyphMapping_.End())
     {
     {
-        FontGlyph& glyph = glyphs_[i->second_];
+        FontGlyph& glyph = i->second_;
         glyph.used_ = true;
         glyph.used_ = true;
         return &glyph;
         return &glyph;
     }
     }
@@ -77,30 +71,22 @@ const FontGlyph* FontFace::GetGlyph(unsigned c)
 
 
 short FontFace::GetKerning(unsigned c, unsigned d) const
 short FontFace::GetKerning(unsigned c, unsigned d) const
 {
 {
-    if (!hasKerning_)
+    if (kerningMapping_.Empty())
         return 0;
         return 0;
 
 
     if (c == '\n' || d == '\n')
     if (c == '\n' || d == '\n')
         return 0;
         return 0;
 
 
-    unsigned leftIndex = 0;
-    unsigned rightIndex = 0;
-    HashMap<unsigned, unsigned>::ConstIterator leftIt = glyphMapping_.Find(c);
-    if (leftIt != glyphMapping_.End())
-        leftIndex = leftIt->second_;
-    else
-        return 0;
-    HashMap<unsigned, unsigned>::ConstIterator rightIt = glyphMapping_.Find(d);
-    if (rightIt != glyphMapping_.End())
-        rightIndex = rightIt->second_;
-    else
+    if (c > 0xffff || d > 0xffff)
         return 0;
         return 0;
 
 
-    HashMap<unsigned, unsigned>::ConstIterator kerningIt = glyphs_[leftIndex].kerning_.Find(rightIndex);
-    if (kerningIt != glyphs_[leftIndex].kerning_.End())
-        return kerningIt->second_;
-    else
-        return 0;
+    unsigned value = (c << 16) + d;
+
+    HashMap<unsigned, short>::ConstIterator i = kerningMapping_.Find(value);
+    if (i != kerningMapping_.End())
+        return i->second_;
+
+    return 0;
 }
 }
 
 
 bool FontFace::IsDataLost() const
 bool FontFace::IsDataLost() const

+ 8 - 28
Source/Engine/UI/FontFace.h

@@ -33,26 +33,12 @@ class Font;
 class Image;
 class Image;
 class Texture2D;
 class Texture2D;
 
 
-/// Mutable font glyph description.
-struct MutableGlyph
-{
-    /// Construct.
-    MutableGlyph();
-    
-    /// The actual glyph index that currently occupies this mutable slot. M_MAX_UNSIGNED if none.
-    unsigned glyphIndex_;
-    /// X position in texture.
-    short x_;
-    /// Y position in texture.
-    short y_;
-};
-
 /// %Font glyph description.
 /// %Font glyph description.
 struct FontGlyph
 struct FontGlyph
 {
 {
     /// Construct.
     /// Construct.
     FontGlyph();
     FontGlyph();
-    
+
     /// X position in texture.
     /// X position in texture.
     short x_;
     short x_;
     /// Y position in texture.
     /// Y position in texture.
@@ -71,23 +57,19 @@ struct FontGlyph
     unsigned page_;
     unsigned page_;
     /// Used flag.
     /// Used flag.
     bool used_;
     bool used_;
-    /// Kerning information.
-    HashMap<unsigned, unsigned> kerning_;
-    /// Mutable glyph list iterator.
-    List<MutableGlyph*>::Iterator iterator_;
 };
 };
 
 
 /// %Font face description.
 /// %Font face description.
 class URHO3D_API FontFace : public RefCounted
 class URHO3D_API FontFace : public RefCounted
 {
 {
     friend class Font;
     friend class Font;
-    
+
 public:
 public:
     /// Construct.
     /// Construct.
     FontFace(Font* font);
     FontFace(Font* font);
     /// Destruct.
     /// Destruct.
     ~FontFace();
     ~FontFace();
-    
+
     /// Load font face.
     /// Load font face.
     virtual bool Load(const unsigned char* fontData, unsigned fontDataSize, int pointSize) = 0;
     virtual bool Load(const unsigned char* fontData, unsigned fontDataSize, int pointSize) = 0;
     /// Return pointer to the glyph structure corresponding to a character. Return null if glyph not found.
     /// Return pointer to the glyph structure corresponding to a character. Return null if glyph not found.
@@ -104,7 +86,7 @@ public:
     int GetRowHeight() const { return rowHeight_; }
     int GetRowHeight() const { return rowHeight_; }
     /// Return textures.
     /// Return textures.
     const Vector<SharedPtr<Texture2D> >& GetTextures() const { return textures_; }
     const Vector<SharedPtr<Texture2D> >& GetTextures() const { return textures_; }
-    
+
 protected:
 protected:
     friend class FontFaceBitmap;
     friend class FontFaceBitmap;
     /// Create a texture for font rendering.
     /// Create a texture for font rendering.
@@ -114,18 +96,16 @@ protected:
 
 
     /// Parent font.
     /// Parent font.
     Font* font_;
     Font* font_;
-    /// Glyphs.
-    Vector<FontGlyph> glyphs_;
-    /// Glyph index mapping.
-    HashMap<unsigned, unsigned> glyphMapping_;
+    /// Glyph mapping.
+    HashMap<unsigned, FontGlyph> glyphMapping_;
+    /// Kerning mapping.
+    HashMap<unsigned, short> kerningMapping_;
     /// Glyph texture pages.
     /// Glyph texture pages.
     Vector<SharedPtr<Texture2D> > textures_;
     Vector<SharedPtr<Texture2D> > textures_;
     /// Point size.
     /// Point size.
     int pointSize_;
     int pointSize_;
     /// Row height.
     /// Row height.
     int rowHeight_;
     int rowHeight_;
-    /// Kerning flag.
-    bool hasKerning_;
 };
 };
 
 
 }
 }

+ 105 - 120
Source/Engine/UI/FontFaceBitmap.cpp

@@ -119,13 +119,12 @@ bool FontFaceBitmap::Load(const unsigned char* fontData, unsigned fontDataSize,
 
 
     XMLElement charsElem = root.GetChild("chars");
     XMLElement charsElem = root.GetChild("chars");
     int count = charsElem.GetInt("count");
     int count = charsElem.GetInt("count");
-    glyphs_.Reserve(count);
-    unsigned index = 0;
 
 
     XMLElement charElem = charsElem.GetChild("char");
     XMLElement charElem = charsElem.GetChild("char");
     while (!charElem.IsNull())
     while (!charElem.IsNull())
     {
     {
         int id = charElem.GetInt("id");
         int id = charElem.GetInt("id");
+
         FontGlyph glyph;
         FontGlyph glyph;
         glyph.x_ = charElem.GetInt("x");
         glyph.x_ = charElem.GetInt("x");
         glyph.y_ = charElem.GetInt("y");
         glyph.y_ = charElem.GetInt("y");
@@ -135,30 +134,22 @@ bool FontFaceBitmap::Load(const unsigned char* fontData, unsigned fontDataSize,
         glyph.offsetY_ = charElem.GetInt("yoffset");
         glyph.offsetY_ = charElem.GetInt("yoffset");
         glyph.advanceX_ = charElem.GetInt("xadvance");
         glyph.advanceX_ = charElem.GetInt("xadvance");
         glyph.page_ = charElem.GetInt("page");
         glyph.page_ = charElem.GetInt("page");
-        glyphs_.Push(glyph);
-        glyphMapping_[id] = index++;
+
+        glyphMapping_[id] = glyph;
 
 
         charElem = charElem.GetNext("char");
         charElem = charElem.GetNext("char");
     }
     }
 
 
     XMLElement kerningsElem = root.GetChild("kernings");
     XMLElement kerningsElem = root.GetChild("kernings");
-    if (kerningsElem.IsNull())
-        hasKerning_ = false;
-    else
+    if (kerningsElem.NotNull())
     {
     {
         XMLElement kerningElem = kerningsElem.GetChild("kerning");
         XMLElement kerningElem = kerningsElem.GetChild("kerning");
         while (!kerningElem.IsNull())
         while (!kerningElem.IsNull())
         {
         {
             int first = kerningElem.GetInt("first");
             int first = kerningElem.GetInt("first");
-            HashMap<unsigned, unsigned>::Iterator i = glyphMapping_.Find(first);
-            if (i != glyphMapping_.End())
-            {
-                int second = kerningElem.GetInt("second");
-                int amount = kerningElem.GetInt("amount");
-
-                FontGlyph& glyph = glyphs_[i->second_];
-                glyph.kerning_[second] = amount;
-            }
+            int second = kerningElem.GetInt("second");
+            unsigned value = (first << 16) + second;
+            kerningMapping_[value] = (short)kerningElem.GetInt("amount");
 
 
             kerningElem = kerningElem.GetNext("kerning");
             kerningElem = kerningElem.GetNext("kerning");
         }
         }
@@ -172,105 +163,94 @@ bool FontFaceBitmap::Load(const unsigned char* fontData, unsigned fontDataSize,
 
 
 bool FontFaceBitmap::Load(FontFace* fontFace, bool usedGlyphs)
 bool FontFaceBitmap::Load(FontFace* fontFace, bool usedGlyphs)
 {
 {
-    Context* context = font_->GetContext();
-    int maxTextureSize = font_->GetSubsystem<UI>()->GetMaxFontTextureSize();
+    if (this == fontFace)
+        return true;
+
+    if (!usedGlyphs)
+    {
+        glyphMapping_ = fontFace->glyphMapping_;
+        kerningMapping_ = fontFace->kerningMapping_;
+        textures_ = fontFace->textures_;
+        pointSize_ = fontFace->pointSize_;
+        rowHeight_ = fontFace->rowHeight_;
+
+        return true;
+    }
 
 
-    // Clone properties
     pointSize_ = fontFace->pointSize_;
     pointSize_ = fontFace->pointSize_;
     rowHeight_ = fontFace->rowHeight_;
     rowHeight_ = fontFace->rowHeight_;
-    hasKerning_ = fontFace->hasKerning_;
+
+    int numPages = 1;
+    int maxTextureSize = font_->GetSubsystem<UI>()->GetMaxFontTextureSize();
+    AreaAllocator allocator(FONT_TEXTURE_MIN_SIZE, FONT_TEXTURE_MIN_SIZE, maxTextureSize, maxTextureSize);
+
+    for (HashMap<unsigned, FontGlyph>::ConstIterator i = fontFace->glyphMapping_.Begin(); i != fontFace->glyphMapping_.End(); ++i)
+    {
+        FontGlyph fontGlyph = i->second_;
+        if (!fontGlyph.used_)
+            continue;
+
+        int x, y;
+        if (!allocator.Allocate(fontGlyph.width_ + 1, fontGlyph.height_ + 1, x, y))
+        {
+            ++numPages;
+
+            allocator = AreaAllocator(FONT_TEXTURE_MIN_SIZE, FONT_TEXTURE_MIN_SIZE, maxTextureSize, maxTextureSize);
+            if (!allocator.Allocate(fontGlyph.width_ + 1, fontGlyph.height_ + 1, x, y))
+                return false;
+        }
+
+        fontGlyph.x_ = x;
+        fontGlyph.y_ = y;
+        fontGlyph.page_ = numPages - 1;
+
+        glyphMapping_[i->first_] = fontGlyph;
+    }
 
 
     // Assume that format is the same for all textures and that bitmap font type may have more than one component
     // Assume that format is the same for all textures and that bitmap font type may have more than one component
     unsigned components = ConvertFormatToNumComponents(fontFace->textures_[0]->GetFormat());
     unsigned components = ConvertFormatToNumComponents(fontFace->textures_[0]->GetFormat());
 
 
     // Save the existing textures as image resources
     // Save the existing textures as image resources
-    Vector<SharedPtr<Image> > images(fontFace->textures_.Size());
+    Vector<SharedPtr<Image> > oldImages;
     for (unsigned i = 0; i < fontFace->textures_.Size(); ++i)
     for (unsigned i = 0; i < fontFace->textures_.Size(); ++i)
-        images[i] = SaveFaceTexture(fontFace->textures_[i]);
-
-    // Reallocate used glyphs to new texture(s)
-    unsigned page = 0;
-    unsigned index = 0;
-    unsigned startIndex = 0;
-    HashMap<unsigned, unsigned>::ConstIterator startIter = fontFace->glyphMapping_.Begin();
-    HashMap<unsigned, unsigned>::ConstIterator i;
-    while (startIter != fontFace->glyphMapping_.End())
+        oldImages.Push(SaveFaceTexture(fontFace->textures_[i]));
+
+    Vector<SharedPtr<Image> > newImages(numPages);
+    for (int i = 0; i < numPages; ++i)
     {
     {
-        AreaAllocator allocator(FONT_TEXTURE_MIN_SIZE, FONT_TEXTURE_MIN_SIZE, maxTextureSize, maxTextureSize);
-        for (i = startIter; i != fontFace->glyphMapping_.End(); ++i)
+        SharedPtr<Image> image(new Image(font_->GetContext()));
+
+        int width = maxTextureSize;
+        int height = maxTextureSize;
+        if (i == numPages - 1)
         {
         {
-            FontGlyph glyph = fontFace->glyphs_[i->second_];
-            if (!glyph.used_)
-                continue;
-
-            if (glyph.width_ && glyph.height_)
-            {
-                int x, y;
-                // Reserve an empty border between glyphs for filtering
-                if (allocator.Allocate(glyph.width_ + 1, glyph.height_ + 1, x, y))
-                {
-                    glyph.x_ = x;
-                    glyph.y_ = y;
-                    glyph.page_ = page;
-                }
-                else
-                    break;
-            }
-
-            glyphs_.Push(glyph);
-            glyphMapping_[i->first_] = index++;
+            width = allocator.GetWidth();
+            height = allocator.GetHeight();
         }
         }
 
 
-        int texWidth = allocator.GetWidth();
-        int texHeight = allocator.GetHeight();
-
-        // Create the image for rendering the fonts
-        SharedPtr<Image> image(new Image(context));
-        image->SetSize(texWidth, texHeight, components);
+        image->SetSize(width, height, components);
+        memset(image->GetData(), 0, width * height * components);
 
 
-        // First clear the whole image
-        unsigned char* imageData = image->GetData();
-        for (int y = 0; y < texHeight; ++y)
-        {
-            unsigned char* dest = imageData + components * texWidth * y;
-            memset(dest, 0, components * texWidth);
-        }
+        newImages.Push(image);
+    }
 
 
-        // Then render the glyphs into new image
-        for (HashMap<unsigned, unsigned>::ConstIterator j = startIter; j != i; ++j)
-        {
-            FontGlyph glyph = fontFace->glyphs_[j->second_];
-            if (!glyph.used_)
-                continue;
-
-            if (!glyph.width_ || !glyph.height_)
-            {
-                ++startIndex;
-                continue;
-            }
-
-            FontGlyph packedGlyph = glyphs_[startIndex++];
-
-            Image* image = images[glyph.page_];
-            unsigned char* source = image->GetData() + components * (image->GetWidth() * glyph.y_ + glyph.x_);
-            unsigned char* destination = imageData + components * (texWidth * packedGlyph.y_ + packedGlyph.x_);
-            for (int i = 0; i < glyph.height_; ++i)
-            {
-                memcpy(destination, source, components * glyph.width_);
-                source += components * image->GetWidth();
-                destination += components * texWidth;
-            }
-        }
+    for (HashMap<unsigned, FontGlyph>::Iterator i = glyphMapping_.Begin(); i != glyphMapping_.End(); ++i)
+    {
+        FontGlyph& newGlyph = i->second_;
+        const FontGlyph& oldGlyph = fontFace->glyphMapping_[i->first_];
+        Blit(newImages[newGlyph.page_], newGlyph.x_, newGlyph.y_, newGlyph.width_, newGlyph.height_, oldImages[oldGlyph.page_], oldGlyph.x_, oldGlyph.y_, components);
+    }
 
 
-        // Finally load image into the texture
-        SharedPtr<Texture2D> texture = LoadFaceTexture(image);
-        if (!texture)
-            return false;
-        textures_.Push(texture);
+    textures_.Resize(newImages.Size());
+    for (unsigned i = 0; i < newImages.Size(); ++i)
+        textures_[i] = LoadFaceTexture(newImages[i]);
 
 
-        ++page;
-        startIter = i;
-        assert(index == startIndex);
+    for (HashMap<unsigned, short>::ConstIterator i = fontFace->kerningMapping_.Begin(); i != fontFace->kerningMapping_.End(); ++i)
+    {
+        unsigned first = (i->first_) >> 16;
+        unsigned second = (i->first_) & 0xffff;
+        if (glyphMapping_.Find(first) != glyphMapping_.End() && glyphMapping_.Find(second) != glyphMapping_.End())
+            kerningMapping_[i->first_] = i->second_;
     }
     }
 
 
     return true;
     return true;
@@ -300,7 +280,7 @@ bool FontFaceBitmap::Save(Serializer& dest, int pointSize)
     File* file = dynamic_cast<File*>(&dest);
     File* file = dynamic_cast<File*>(&dest);
     if (file)
     if (file)
         // If serialize to file, use the file's path
         // If serialize to file, use the file's path
-            pathName = GetPath(file->GetName());
+        pathName = GetPath(file->GetName());
     else
     else
         // Otherwise, use the font resource's path
         // Otherwise, use the font resource's path
         pathName = "Data/" + GetPath(font_->GetName());
         pathName = "Data/" + GetPath(font_->GetName());
@@ -320,18 +300,16 @@ bool FontFaceBitmap::Save(Serializer& dest, int pointSize)
 
 
     // Chars and kernings
     // Chars and kernings
     XMLElement charsElem = rootElem.CreateChild("chars");
     XMLElement charsElem = rootElem.CreateChild("chars");
-    unsigned numGlyphs = glyphs_.Size();
+    unsigned numGlyphs = glyphMapping_.Size();
     charsElem.SetInt("count", numGlyphs);
     charsElem.SetInt("count", numGlyphs);
-    XMLElement kerningsElem;
-    bool hasKerning = hasKerning_;
-    if (hasKerning)
-        kerningsElem = rootElem.CreateChild("kernings");
-    for (HashMap<unsigned, unsigned>::ConstIterator i = glyphMapping_.Begin(); i != glyphMapping_.End(); ++i)
+
+    for (HashMap<unsigned, FontGlyph>::ConstIterator i = glyphMapping_.Begin(); i != glyphMapping_.End(); ++i)
     {
     {
         // Char
         // Char
         XMLElement charElem = charsElem.CreateChild("char");
         XMLElement charElem = charsElem.CreateChild("char");
         charElem.SetInt("id", i->first_);
         charElem.SetInt("id", i->first_);
-        FontGlyph glyph = glyphs_[i->second_];
+
+        const FontGlyph& glyph = i->second_;
         charElem.SetInt("x", glyph.x_);
         charElem.SetInt("x", glyph.x_);
         charElem.SetInt("y", glyph.y_);
         charElem.SetInt("y", glyph.y_);
         charElem.SetInt("width", glyph.width_);
         charElem.SetInt("width", glyph.width_);
@@ -340,21 +318,17 @@ bool FontFaceBitmap::Save(Serializer& dest, int pointSize)
         charElem.SetInt("yoffset", glyph.offsetY_);
         charElem.SetInt("yoffset", glyph.offsetY_);
         charElem.SetInt("xadvance", glyph.advanceX_);
         charElem.SetInt("xadvance", glyph.advanceX_);
         charElem.SetInt("page", glyph.page_);
         charElem.SetInt("page", glyph.page_);
+    }
 
 
-        // Kerning
-        if (hasKerning)
+    if (!kerningMapping_.Empty())
+    {
+        XMLElement kerningsElem = rootElem.CreateChild("kernings");
+        for (HashMap<unsigned, short>::ConstIterator i = kerningMapping_.Begin(); i != kerningMapping_.End(); ++i)
         {
         {
-            for (HashMap<unsigned, unsigned>::ConstIterator j = glyph.kerning_.Begin(); j != glyph.kerning_.End(); ++j)
-            {
-                // To conserve space, only write when amount is non zero
-                if (j->second_ == 0)
-                    continue;
-
-                XMLElement kerningElem = kerningsElem.CreateChild("kerning");
-                kerningElem.SetInt("first", i->first_);
-                kerningElem.SetInt("second", j->first_);
-                kerningElem.SetInt("amount", j->second_);
-            }
+            XMLElement kerningElem = kerningsElem.CreateChild("kerning");
+            kerningElem.SetInt("first", i->first_ >> 16);
+            kerningElem.SetInt("second", i->first_ & 0xffff);
+            kerningElem.SetInt("amount", i->second_);
         }
         }
     }
     }
 
 
@@ -373,7 +347,6 @@ unsigned FontFaceBitmap::ConvertFormatToNumComponents(unsigned format)
         return 1;
         return 1;
 }
 }
 
 
-
 SharedPtr<Image> FontFaceBitmap::SaveFaceTexture(Texture2D* texture)
 SharedPtr<Image> FontFaceBitmap::SaveFaceTexture(Texture2D* texture)
 {
 {
     Image* image = new Image(font_->GetContext());
     Image* image = new Image(font_->GetContext());
@@ -393,4 +366,16 @@ bool FontFaceBitmap::SaveFaceTexture(Texture2D* texture, const String& fileName)
     return image ? image->SavePNG(fileName) : false;
     return image ? image->SavePNG(fileName) : false;
 }
 }
 
 
+void FontFaceBitmap::Blit(Image* dest, int x, int y, int width, int height, Image* source, int sourceX, int sourceY, int components)
+{
+    unsigned char* destData = dest->GetData() + (y * dest->GetWidth() + x) * components;
+    unsigned char* sourceData = source->GetData() + (sourceY * source->GetWidth() + sourceX) * components;
+    for (int i = 0; i < height; ++i)
+    {
+        memcpy(destData, sourceData, width * components);
+        destData += dest->GetWidth() * components;
+        sourceData += source->GetWidth() * components;
+    }
+}
+
 }
 }

+ 2 - 0
Source/Engine/UI/FontFaceBitmap.h

@@ -53,6 +53,8 @@ private:
     SharedPtr<Image> SaveFaceTexture(Texture2D* texture);
     SharedPtr<Image> SaveFaceTexture(Texture2D* texture);
     /// Save font face texture as image file.
     /// Save font face texture as image file.
     bool SaveFaceTexture(Texture2D* texture, const String& fileName);
     bool SaveFaceTexture(Texture2D* texture, const String& fileName);
+    /// Blit.
+    void Blit(Image* dest, int x, int y, int width, int height, Image* source, int sourceX, int sourceY, int components);
 };
 };
 
 
 }
 }

+ 171 - 235
Source/Engine/UI/FontFaceFreeType.cpp

@@ -50,19 +50,19 @@ public:
     /// Construct.
     /// Construct.
     FreeTypeLibrary(Context* context) :
     FreeTypeLibrary(Context* context) :
         Object(context)
         Object(context)
-    {
-        FT_Error error = FT_Init_FreeType(&library_);
-        if (error)
-            LOGERROR("Could not initialize FreeType library");
-    }
+        {
+            FT_Error error = FT_Init_FreeType(&library_);
+            if (error)
+                LOGERROR("Could not initialize FreeType library");
+        }
 
 
-    /// Destruct.
-    virtual ~FreeTypeLibrary()
-    {
-        FT_Done_FreeType(library_);
-    }
+        /// Destruct.
+        virtual ~FreeTypeLibrary()
+        {
+            FT_Done_FreeType(library_);
+        }
 
 
-    FT_Library GetLibrary() const { return library_; }
+        FT_Library GetLibrary() const { return library_; }
 
 
 private:
 private:
     /// FreeType library.
     /// FreeType library.
@@ -70,9 +70,8 @@ private:
 };
 };
 
 
 FontFaceFreeType::FontFaceFreeType(Font* font) :
 FontFaceFreeType::FontFaceFreeType(Font* font) :
-    FontFace(font),
-    face_(0),
-    bitmapSize_(0)
+FontFace(font),
+    face_(0)
 {
 {
 
 
 }
 }
@@ -84,10 +83,6 @@ FontFaceFreeType::~FontFaceFreeType()
         FT_Done_Face((FT_Face)face_);
         FT_Done_Face((FT_Face)face_);
         face_ = 0;
         face_ = 0;
     }
     }
-
-    for (List<MutableGlyph*>::Iterator i = mutableGlyphs_.Begin(); i != mutableGlyphs_.End(); ++i)
-        delete *i;
-    mutableGlyphs_.Clear();
 }
 }
 
 
 bool FontFaceFreeType::Load(const unsigned char* fontData, unsigned fontDataSize, int pointSize)
 bool FontFaceFreeType::Load(const unsigned char* fontData, unsigned fontDataSize, int pointSize)
@@ -136,15 +131,16 @@ bool FontFaceFreeType::Load(const unsigned char* fontData, unsigned fontDataSize
     face_ = face;
     face_ = face;
 
 
     FT_GlyphSlot slot = face->glyph;
     FT_GlyphSlot slot = face->glyph;
-    unsigned numGlyphs = 0;
 
 
-    // Build glyph mapping
     FT_UInt glyphIndex;
     FT_UInt glyphIndex;
+    unsigned numGlyphs = 0;
+    HashMap<unsigned, unsigned> indexToCharMapping;
+
     FT_ULong charCode = FT_Get_First_Char(face, &glyphIndex);
     FT_ULong charCode = FT_Get_First_Char(face, &glyphIndex);
     while (glyphIndex != 0)
     while (glyphIndex != 0)
     {
     {
         numGlyphs = Max((int)glyphIndex + 1, (int)numGlyphs);
         numGlyphs = Max((int)glyphIndex + 1, (int)numGlyphs);
-        glyphMapping_[charCode] = glyphIndex;
+        indexToCharMapping[glyphIndex] = charCode;
         charCode = FT_Get_Next_Char(face, charCode, &glyphIndex);
         charCode = FT_Get_Next_Char(face, charCode, &glyphIndex);
     }
     }
 
 
@@ -154,59 +150,53 @@ bool FontFaceFreeType::Load(const unsigned char* fontData, unsigned fontDataSize
     int maxWidth = 0;
     int maxWidth = 0;
     int maxHeight = 0;
     int maxHeight = 0;
     int loadMode = ui->GetForceAutoHint() ? FT_LOAD_FORCE_AUTOHINT : FT_LOAD_DEFAULT;
     int loadMode = ui->GetForceAutoHint() ? FT_LOAD_FORCE_AUTOHINT : FT_LOAD_DEFAULT;
-    int ascender = face->size->metrics.ascender >> 6;
+    ascender_ = face->size->metrics.ascender >> 6;
     int descender = face->size->metrics.descender >> 6;
     int descender = face->size->metrics.descender >> 6;
 
 
     // Check if the font's OS/2 info gives different (larger) values for ascender & descender
     // Check if the font's OS/2 info gives different (larger) values for ascender & descender
     TT_OS2* os2Info = (TT_OS2*)FT_Get_Sfnt_Table(face, ft_sfnt_os2);
     TT_OS2* os2Info = (TT_OS2*)FT_Get_Sfnt_Table(face, ft_sfnt_os2);
     if (os2Info)
     if (os2Info)
     {
     {
-        ascender = Max(ascender, os2Info->usWinAscent * face->size->metrics.y_ppem / face->units_per_EM);
-        ascender = Max(ascender, os2Info->sTypoAscender * face->size->metrics.y_ppem / face->units_per_EM);
+        ascender_ = Max(ascender_, os2Info->usWinAscent * face->size->metrics.y_ppem / face->units_per_EM);
+        ascender_ = Max(ascender_, os2Info->sTypoAscender * face->size->metrics.y_ppem / face->units_per_EM);
         descender = Max(descender, os2Info->usWinDescent * face->size->metrics.y_ppem / face->units_per_EM);
         descender = Max(descender, os2Info->usWinDescent * face->size->metrics.y_ppem / face->units_per_EM);
         descender = Max(descender, os2Info->sTypoDescender * face->size->metrics.y_ppem / face->units_per_EM);
         descender = Max(descender, os2Info->sTypoDescender * face->size->metrics.y_ppem / face->units_per_EM);
     }
     }
 
 
     // Store point size and row height. Use the maximum of ascender + descender, or the face's stored default row height
     // Store point size and row height. Use the maximum of ascender + descender, or the face's stored default row height
     pointSize_ = pointSize;
     pointSize_ = pointSize;
-    rowHeight_ = Max(ascender + descender, face->size->metrics.height >> 6);
+    rowHeight_ = Max(ascender_ + descender, face->size->metrics.height >> 6);
+
+    int textureWidth = maxTextureSize;
+    int textureHeight = maxTextureSize;
+    bool loadAllGlyphs = CanLoadAllGlyphs(numGlyphs, loadMode, textureWidth, textureHeight);
 
 
-    glyphs_.Reserve(numGlyphs);
+    SharedPtr<Image> image(new Image(font_->GetContext()));
+    image->SetSize(textureWidth, textureHeight, 1);
+    unsigned char* imageData = image->GetData();
+    memset(imageData, 0, image->GetWidth() * image->GetHeight());
+    allocator_ = AreaAllocator(FONT_TEXTURE_MIN_SIZE, FONT_TEXTURE_MIN_SIZE, textureWidth, textureHeight);
 
 
     for (unsigned i = 0; i < numGlyphs; ++i)
     for (unsigned i = 0; i < numGlyphs; ++i)
     {
     {
-        FontGlyph newGlyph;
-
-        error = FT_Load_Glyph(face, i, loadMode);
-        if (!error)
-        {
-            // Note: position within texture will be filled later
-            newGlyph.width_ = (short)Max(slot->metrics.width >> 6, slot->bitmap.width);
-            newGlyph.height_ = (short)Max(slot->metrics.height >> 6, slot->bitmap.rows);
-            newGlyph.offsetX_ = (short)(slot->metrics.horiBearingX >> 6);
-            newGlyph.offsetY_ = (short)(ascender - (slot->metrics.horiBearingY >> 6));
-            newGlyph.advanceX_ = (short)(slot->metrics.horiAdvance >> 6);
-
-            maxWidth = Max(maxWidth, newGlyph.width_);
-            maxHeight = Max(maxHeight, newGlyph.height_);
-        }
-        else
-        {
-            newGlyph.width_ = 0;
-            newGlyph.height_ = 0;
-            newGlyph.offsetX_ = 0;
-            newGlyph.offsetY_ = 0;
-            newGlyph.advanceX_ = 0;
-        }
+        unsigned charCode = indexToCharMapping[i];
+        if (!loadAllGlyphs && (charCode > 0xff))
+            break;
 
 
-        glyphs_.Push(newGlyph);
+        if (!LoadCharGlyph(charCode, image))
+            return false;
     }
     }
 
 
+    SharedPtr<Texture2D> texture = LoadFaceTexture(image);
+    if (!texture)
+        return false;
+
+    textures_.Push(texture);
+    font_->SetMemoryUse(font_->GetMemoryUse() + textureWidth * textureHeight);
+
     // Store kerning if face has kerning information
     // Store kerning if face has kerning information
     if (FT_HAS_KERNING(face))
     if (FT_HAS_KERNING(face))
     {
     {
-        hasKerning_ = true;
-
         // Read kerning manually to be more efficient and avoid out of memory crash when use large font file, for example there
         // Read kerning manually to be more efficient and avoid out of memory crash when use large font file, for example there
         // are 29354 glyphs in msyh.ttf
         // are 29354 glyphs in msyh.ttf
         FT_ULong tag = FT_MAKE_TAG('k', 'e', 'r', 'n');
         FT_ULong tag = FT_MAKE_TAG('k', 'e', 'r', 'n');
@@ -252,8 +242,14 @@ bool FontFaceFreeType::Load(const unsigned char* fontData, unsigned fontDataSize
                         unsigned leftIndex = deserializer.ReadUShort();
                         unsigned leftIndex = deserializer.ReadUShort();
                         unsigned rightIndex = deserializer.ReadUShort();
                         unsigned rightIndex = deserializer.ReadUShort();
                         short amount = (short)(deserializer.ReadShort() >> 6);
                         short amount = (short)(deserializer.ReadShort() >> 6);
-                        if (leftIndex < numGlyphs && rightIndex < numGlyphs)
-                            glyphs_[leftIndex].kerning_[rightIndex] = amount;
+
+                        HashMap<unsigned, unsigned>::ConstIterator leftIter = indexToCharMapping.Find(leftIndex);
+                        HashMap<unsigned, unsigned>::ConstIterator rightIter = indexToCharMapping.Find(rightIndex);
+                        if (leftIter != indexToCharMapping.End() && rightIter != indexToCharMapping.End())
+                        {
+                            unsigned value = (leftIter->second_ << 16) + rightIter->second_;
+                            kerningMapping_[value] = amount;
+                        }
                         else
                         else
                             LOGWARNING("Out of range glyph index in kerning information");
                             LOGWARNING("Out of range glyph index in kerning information");
                     }
                     }
@@ -269,250 +265,190 @@ bool FontFaceFreeType::Load(const unsigned char* fontData, unsigned fontDataSize
             LOGWARNING("Can not read kerning information: not version 0");
             LOGWARNING("Can not read kerning information: not version 0");
     }
     }
 
 
-    // Now try to pack into the smallest possible texture. If face does not fit into one texture, enable dynamic mode where
-    // glyphs are only created as necessary
-    if (RenderAllGlyphs(maxTextureSize, maxTextureSize))
+    if (loadAllGlyphs)
     {
     {
         FT_Done_Face(face);
         FT_Done_Face(face);
         face_ = 0;
         face_ = 0;
+        hasMutableGlyph_ = false;
     }
     }
     else
     else
-    {
-        if (ui->GetUseMutableGlyphs())
-            SetupMutableGlyphs(maxTextureSize, maxTextureSize, maxWidth, maxHeight);
-        else
-            SetupNextTexture(maxTextureSize, maxTextureSize);
-    }
+        hasMutableGlyph_ = true;
 
 
     return true;
     return true;
 }
 }
 
 
 const FontGlyph* FontFaceFreeType::GetGlyph(unsigned c)
 const FontGlyph* FontFaceFreeType::GetGlyph(unsigned c)
 {
 {
-    HashMap<unsigned, unsigned>::ConstIterator i = glyphMapping_.Find(c);
+    HashMap<unsigned, FontGlyph>::Iterator i = glyphMapping_.Find(c);
     if (i != glyphMapping_.End())
     if (i != glyphMapping_.End())
     {
     {
-        FontGlyph& glyph = glyphs_[i->second_];
-        // 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
-        if (mutableGlyphs_.Size() && glyph.iterator_ != mutableGlyphs_.End())
-        {
-            MutableGlyph* mutableGlyph = *glyph.iterator_;
-            mutableGlyphs_.Erase(glyph.iterator_);
-            mutableGlyphs_.PushFront(mutableGlyph);
-            glyph.iterator_ = mutableGlyphs_.Begin();
-        }
-
+        FontGlyph& glyph = i->second_;
         glyph.used_ = true;
         glyph.used_ = true;
         return &glyph;
         return &glyph;
     }
     }
-    else
-        return 0;
+
+    if (LoadCharGlyph(c))
+    {
+        HashMap<unsigned, FontGlyph>::Iterator i = glyphMapping_.Find(c);
+        if (i != glyphMapping_.End())
+        {
+            FontGlyph& glyph = i->second_;
+            glyph.used_ = true;
+            return &glyph;
+        }
+    }
+
+    return 0;
 }
 }
 
 
-bool FontFaceFreeType::RenderAllGlyphs(int maxWidth, int maxHeight)
+bool FontFaceFreeType::CanLoadAllGlyphs(unsigned numGlyphs, int loadMode, int& textureWidth, int& textureHeight) const
 {
 {
-    assert(font_ && face_ && textures_.Empty());
-
-    allocator_ = AreaAllocator(FONT_TEXTURE_MIN_SIZE, FONT_TEXTURE_MIN_SIZE, maxWidth, maxHeight);
+    FT_Face face = (FT_Face)face_;
+    FT_GlyphSlot slot = face->glyph;
+    AreaAllocator allocator(FONT_TEXTURE_MIN_SIZE, FONT_TEXTURE_MIN_SIZE, textureWidth, textureHeight);
 
 
-    for (unsigned i = 0; i < glyphs_.Size(); ++i)
+    for (unsigned i = 0; i < numGlyphs; ++i)
     {
     {
-        if (glyphs_[i].width_ && glyphs_[i].height_)
+        FT_Error error = FT_Load_Glyph(face, i, loadMode);
+        if (!error)
         {
         {
+            int width = Max(slot->metrics.width >> 6, slot->bitmap.width);
+            int height = Max(slot->metrics.height >> 6, slot->bitmap.rows);
             int x, y;
             int x, y;
-            // Reserve an empty border between glyphs for filtering
-            if (allocator_.Allocate(glyphs_[i].width_ + 1, glyphs_[i].height_ + 1, x, y))
-            {
-                glyphs_[i].x_ = x;
-                glyphs_[i].y_ = y;
-                glyphs_[i].page_ = 0;
-            }
-            else
-            {
-                // When allocation fails, reset the page of all glyphs allocated so far
-                for (unsigned j = 0; j <= i; ++j)
-                    glyphs_[j].page_ = M_MAX_UNSIGNED;
+            if (!allocator.Allocate(width + 1, height + 1, x, y))
                 return false;
                 return false;
-            }
-        }
-        else
-        {
-            glyphs_[i].x_ = 0;
-            glyphs_[i].y_ = 0;
-            glyphs_[i].page_ = 0;
         }
         }
     }
     }
 
 
-    // Create image for rendering all the glyphs, clear to black
+    textureWidth = allocator.GetWidth();
+    textureHeight = allocator.GetHeight();
+    return true;
+}
+
+bool FontFaceFreeType::SetupNextTexture(int textureWidth, int textureHeight)
+{
     SharedPtr<Image> image(new Image(font_->GetContext()));
     SharedPtr<Image> image(new Image(font_->GetContext()));
-    image->SetSize(allocator_.GetWidth(), allocator_.GetHeight(), 1);
+    image->SetSize(textureWidth, textureHeight, 1);
     unsigned char* imageData = image->GetData();
     unsigned char* imageData = image->GetData();
     memset(imageData, 0, image->GetWidth() * image->GetHeight());
     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(), loadMode);
-
-    // Load image into a texture, increment memory usage of the parent font
     SharedPtr<Texture2D> texture = LoadFaceTexture(image);
     SharedPtr<Texture2D> texture = LoadFaceTexture(image);
     if (!texture)
     if (!texture)
-    {
-        for (unsigned i = 0; i < glyphs_.Size(); ++i)
-            glyphs_[i].page_ = M_MAX_UNSIGNED;
         return false;
         return false;
-    }
 
 
     textures_.Push(texture);
     textures_.Push(texture);
-    font_->SetMemoryUse(font_->GetMemoryUse() + image->GetWidth() * image->GetHeight());
+    allocator_ = AreaAllocator(FONT_TEXTURE_MIN_SIZE, FONT_TEXTURE_MIN_SIZE, textureWidth, textureHeight);
+
+    font_->SetMemoryUse(font_->GetMemoryUse() + textureWidth * textureHeight);
 
 
-    LOGDEBUGF("Font face %s (%dpt) uses a static page texture of size %dx%d", GetFileName(font_->GetName()).CString(), pointSize_, texture->GetWidth(), texture->GetHeight());
     return true;
     return true;
 }
 }
 
 
-void FontFaceFreeType::RenderGlyph(unsigned index)
+bool FontFaceFreeType::LoadCharGlyph(unsigned charCode, Image* image)
 {
 {
-    assert(font_ && face_);
-
-    FontGlyph& glyph = glyphs_[index];
+    if (!face_)
+        return false;
 
 
-    // If glyph is empty, just set the current page
-    if (!glyph.width_ || !glyph.height_)
-    {
-        glyph.x_ = 0;
-        glyph.y_ = 0;
-        glyph.page_ = textures_.Size() - 1;
-        return;
-    }
+    FT_Face face = (FT_Face)face_;
+    FT_GlyphSlot slot = face->glyph;
 
 
-    int loadMode = font_->GetSubsystem<UI>()->GetForceAutoHint() ? FT_LOAD_FORCE_AUTOHINT : FT_LOAD_DEFAULT;
+    UI* ui = font_->GetSubsystem<UI>();
+    int loadMode = ui->GetForceAutoHint() ? FT_LOAD_FORCE_AUTOHINT : FT_LOAD_DEFAULT;
 
 
-    if (!mutableGlyphs_.Size())
+    FontGlyph fontGlyph;
+    FT_Error error = FT_Load_Char(face, charCode, loadMode);
+    if (!error)
     {
     {
-        // Not using mutable glyphs: try to allocate from current page, reserve next page if fails
-        int x, y;
-        if (!allocator_.Allocate(glyph.width_ + 1, glyph.height_ + 1, x, y))
+        // Note: position within texture will be filled later
+        fontGlyph.width_ = (short)Max(slot->metrics.width >> 6, slot->bitmap.width);
+        fontGlyph.height_ = (short)Max(slot->metrics.height >> 6, slot->bitmap.rows);
+        fontGlyph.offsetX_ = (short)(slot->metrics.horiBearingX >> 6);
+        fontGlyph.offsetY_ = (short)(ascender_ - (slot->metrics.horiBearingY >> 6));
+        fontGlyph.advanceX_ = (short)(slot->metrics.horiAdvance >> 6);
+
+        if (fontGlyph.width_ > 0 && fontGlyph.height_ > 0)
         {
         {
-            SetupNextTexture(textures_[0]->GetWidth(), textures_[0]->GetHeight());
-            // This always succeeds, as it is the first allocation of an empty page
-            allocator_.Allocate(glyph.width_ + 1, glyph.height_ + 1, x, y);
-        }
+            int x, y;
+            if (!allocator_.Allocate(fontGlyph.width_ + 1, fontGlyph.height_ + 1, x, y))
+            {
+                int textureSize = ui->GetMaxFontTextureSize();
+                if (!SetupNextTexture(textureSize, textureSize))
+                    return false;
 
 
-        glyph.x_ = x;
-        glyph.y_ = y;
-        glyph.page_ = textures_.Size() - 1;
+                if (!allocator_.Allocate(fontGlyph.width_ + 1, fontGlyph.height_ + 1, x, y))
+                    return false;
+            }
 
 
-        if (!bitmap_ || (int)bitmapSize_ < glyph.width_ * glyph.height_)
-        {
-            bitmapSize_ = glyph.width_ * glyph.height_;
-            bitmap_ = new unsigned char[bitmapSize_];
-        }
+            fontGlyph.x_ = x;
+            fontGlyph.y_ = y;
 
 
-        RenderGlyphBitmap(index, bitmap_.Get(), glyph.width_, loadMode);
-        textures_.Back()->SetData(0, glyph.x_, glyph.y_, glyph.width_, glyph.height_, bitmap_.Get());
-    }
-    else
-    {
-        // Using mutable glyphs: overwrite the least recently used glyph
-        List<MutableGlyph*>::Iterator it = --mutableGlyphs_.End();
-        MutableGlyph* mutableGlyph = *it;
-        if (mutableGlyph->glyphIndex_ != M_MAX_UNSIGNED)
-            glyphs_[mutableGlyph->glyphIndex_].page_ = M_MAX_UNSIGNED;
-        glyph.x_ = mutableGlyph->x_;
-        glyph.y_ = mutableGlyph->y_;
-        glyph.page_ = 0;
-        glyph.iterator_ = it;
-        mutableGlyph->glyphIndex_ = index;
-
-        if (!bitmap_)
-        {
-            bitmapSize_ = cellWidth_ * cellHeight_;
-            bitmap_ = new unsigned char[bitmapSize_];
-        }
+            unsigned char* dest = 0;
+            unsigned pitch = 0;
+            if (image)
+            {
+                fontGlyph.page_ = 0;
+                dest = image->GetData() + fontGlyph.y_ * image->GetWidth() + fontGlyph.x_;
+                pitch = image->GetWidth();
+            }
+            else
+            {
+                fontGlyph.page_ = textures_.Size() - 1;
+                dest = new unsigned char[fontGlyph.width_ * fontGlyph.height_];
+                pitch = fontGlyph.width_;
+            }
 
 
-        // Clear the cell bitmap before rendering to ensure padding
-        memset(bitmap_.Get(), 0, cellWidth_ * cellHeight_);
-        RenderGlyphBitmap(index, bitmap_.Get(), cellWidth_, loadMode);
-        textures_[0]->SetData(0, glyph.x_, glyph.y_, cellWidth_, cellHeight_, bitmap_.Get());
-    }
-}
+            FT_Render_Glyph(slot, FT_RENDER_MODE_NORMAL);
+            if (slot->bitmap.pixel_mode == FT_PIXEL_MODE_MONO)
+            {
+                for (int y = 0; y < slot->bitmap.rows; ++y)
+                {
+                    unsigned char* src = slot->bitmap.buffer + slot->bitmap.pitch * y;
+                    unsigned char* rowDest = dest + y * pitch;
 
 
-void FontFaceFreeType::RenderGlyphBitmap(unsigned index, unsigned char* dest, unsigned pitch, int loadMode)
-{
-    const FontGlyph& glyph = glyphs_[index];
-    if (!glyph.width_ || !glyph.height_)
-        return;
+                    for (int x = 0; x < slot->bitmap.width; ++x)
+                        rowDest[x] = (src[x >> 3] & (0x80 >> (x & 7))) ? 255 : 0;
+                }
+            }
+            else
+            {
+                for (int y = 0; y < slot->bitmap.rows; ++y)
+                {
+                    unsigned char* src = slot->bitmap.buffer + slot->bitmap.pitch * y;
+                    unsigned char* rowDest = dest + y * pitch;
 
 
-    FT_Face face = (FT_Face)face_;
-    FT_GlyphSlot slot = face->glyph;
-    FT_Load_Glyph(face, index, loadMode);
-    FT_Render_Glyph(slot, FT_RENDER_MODE_NORMAL);
+                    for (int x = 0; x < slot->bitmap.width; ++x)
+                        rowDest[x] = src[x];
+                }
+            }
 
 
-    if (slot->bitmap.pixel_mode == FT_PIXEL_MODE_MONO)
-    {
-        for (int y = 0; y < slot->bitmap.rows; ++y)
+            if (!image)
+            {
+                textures_.Back()->SetData(0, fontGlyph.x_, fontGlyph.y_, fontGlyph.width_, fontGlyph.height_, dest);
+                delete [] dest;
+            }
+        }
+        else
         {
         {
-            unsigned char* src = slot->bitmap.buffer + slot->bitmap.pitch * y;
-            unsigned char* rowDest = dest + y * pitch;
-
-            for (int x = 0; x < slot->bitmap.width; ++x)
-                rowDest[x] = (src[x >> 3] & (0x80 >> (x & 7))) ? 255 : 0;
+            fontGlyph.x_ = 0;
+            fontGlyph.y_ = 0;
+            fontGlyph.page_ = 0;
         }
         }
     }
     }
     else
     else
     {
     {
-        for (int y = 0; y < slot->bitmap.rows; ++y)
-        {
-            unsigned char* src = slot->bitmap.buffer + slot->bitmap.pitch * y;
-            unsigned char* rowDest = dest + y * pitch;
-
-            for (int x = 0; x < slot->bitmap.width; ++x)
-                rowDest[x] = src[x];
-        }
+        fontGlyph.width_ = 0;
+        fontGlyph.height_ = 0;
+        fontGlyph.offsetX_ = 0;
+        fontGlyph.offsetY_ = 0;
+        fontGlyph.advanceX_ = 0;
+        fontGlyph.page_ = 0;
     }
     }
-}
 
 
-void FontFaceFreeType::SetupNextTexture(int width, int height)
-{
-    // If several dynamic textures are needed, use the maximum size to pack as many as possible to one texture
-    allocator_ = AreaAllocator(width, height);
-
-    SharedPtr<Texture2D> texture = CreateFaceTexture();
-    texture->SetSize(width, height, Graphics::GetAlphaFormat());
-    SharedArrayPtr<unsigned char> emptyBitmap(new unsigned char[width * height]);
-    memset(emptyBitmap.Get(), 0, width * height);
-    texture->SetData(0, 0, 0, width, height, emptyBitmap.Get());
-
-    textures_.Push(texture);
-    font_->SetMemoryUse(font_->GetMemoryUse() + width * height);
+    glyphMapping_[charCode] = fontGlyph;
 
 
-    LOGDEBUGF("Font face %s (%dpt) is using %d dynamic page textures of size %dx%d", GetFileName(font_->GetName()).CString(), pointSize_, textures_.Size(), width, height);
+    return true;
 }
 }
 
 
-void FontFaceFreeType::SetupMutableGlyphs(int textureWidth, int textureHeight, int maxWidth, int maxHeight)
-{
-    assert(mutableGlyphs_.Empty());
-
-    SetupNextTexture(textureWidth, textureHeight);
-
-    cellWidth_ = maxWidth + 1;
-    cellHeight_ = maxHeight + 1;
 
 
-    // Allocate as many mutable glyphs as possible
-    int x, y;
-    while (allocator_.Allocate(cellWidth_, cellHeight_, x, y))
-    {
-        MutableGlyph* glyph = new MutableGlyph();
-        glyph->x_ = x;
-        glyph->y_ = y;
-        mutableGlyphs_.Push(glyph);
-    }
-
-    LOGDEBUGF("Font face %s (%dpt) is using %d mutable glyphs", GetFileName(font_->GetName()).CString(), pointSize_, mutableGlyphs_.Size());
-}
 
 
 }
 }

+ 12 - 22
Source/Engine/UI/FontFaceFreeType.h

@@ -44,36 +44,26 @@ public:
     /// Return pointer to the glyph structure corresponding to a character. Return null if glyph not found.
     /// Return pointer to the glyph structure corresponding to a character. Return null if glyph not found.
     virtual const FontGlyph* GetGlyph(unsigned c);
     virtual const FontGlyph* GetGlyph(unsigned c);
     /// Return if font face uses mutable glyphs.
     /// Return if font face uses mutable glyphs.
-    virtual bool HasMutableGlyphs() const { return !mutableGlyphs_.Empty(); }
+    virtual bool HasMutableGlyphs() const { return hasMutableGlyph_; }
 
 
 private:
 private:
-    /// Render all glyphs of the face into a single texture. Return true if could fit them. Called by Font.
-    bool RenderAllGlyphs(int maxWidth, int maxHeight);
-    /// 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, 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.
-    void SetupMutableGlyphs(int textureWidth, int textureHeight, int maxGlyphWidth, int maxGlyphHeight);
+    /// Check can load all glyph in one texture, return true and texture size if can load.
+    bool CanLoadAllGlyphs(unsigned numGlyphs, int loadMode, int& textureWidth, int& textureHeight) const;
+    /// Setup next texture.
+    bool SetupNextTexture(int textureWidth, int textureHeight);
+    /// Load char glyph.
+    bool LoadCharGlyph(unsigned charCode, Image* image = 0);
 
 
-    /// FreeType library.
+        /// FreeType library.
     SharedPtr<FreeTypeLibrary> freeType_;
     SharedPtr<FreeTypeLibrary> freeType_;
     /// FreeType face. Non-null after creation only in dynamic mode.
     /// FreeType face. Non-null after creation only in dynamic mode.
     void* face_;
     void* face_;
-    /// Mutable glyph list.
-    List<MutableGlyph*> mutableGlyphs_;
-    /// Mutable glyph cell width, including 1 pixel padding.
-    int cellWidth_;
-    /// Mutable glyph cell height, including 1 pixel padding.
-    int cellHeight_;
+    /// Has mutable glyph.
+    bool hasMutableGlyph_;
+    /// Ascender.
+    int ascender_;
     /// Glyph area allocator.
     /// Glyph area allocator.
     AreaAllocator allocator_;
     AreaAllocator allocator_;
-    /// Glyph rendering bitmap in dynamic mode.
-    SharedArrayPtr<unsigned char> bitmap_;
-    /// Glyph rendering bitmap byte size.
-    unsigned bitmapSize_;
 };
 };
 
 
 }
 }