From 6d5787d8da9ad1685864668dd4c3d6aa73a563db Mon Sep 17 00:00:00 2001
From: chai <chaifix@163.com>
Date: Fri, 5 Nov 2021 12:14:59 +0800
Subject: TextMeshGenerator

---
 Runtime/GUI/Font.h                  |  3 ++
 Runtime/GUI/TextMeshGenerator.cpp   | 89 ++++++++++++++++++++++++++++++++++---
 Runtime/GUI/TextMeshGenerator.h     | 14 ++++--
 Runtime/GUI/UITextMesh.cpp          | 25 ++++++++---
 Runtime/GUI/UITextMesh.h            | 33 +++++++++++---
 Runtime/Graphics/Color.h            |  6 +++
 Runtime/Scripting/GUI/Font.bind.cpp |  8 +++-
 Runtime/Utilities/UtilMacros.h      |  3 ++
 8 files changed, 159 insertions(+), 22 deletions(-)

(limited to 'Runtime')

diff --git a/Runtime/GUI/Font.h b/Runtime/GUI/Font.h
index cd546af..565fafc 100644
--- a/Runtime/GUI/Font.h
+++ b/Runtime/GUI/Font.h
@@ -31,10 +31,13 @@ namespace character
 
 	union Hash {
 		unsigned int hashCode;
+#pragma pack(1)
 		struct {
 			Unicode codepoint;
 			unsigned short size;//�����С
 		};
+#pragma pack()
+
 		bool operator==(const Hash &other) const
 		{
 			return codepoint == other.codepoint && size == other.size;
diff --git a/Runtime/GUI/TextMeshGenerator.cpp b/Runtime/GUI/TextMeshGenerator.cpp
index 98d3b09..b4c8c4d 100644
--- a/Runtime/GUI/TextMeshGenerator.cpp
+++ b/Runtime/GUI/TextMeshGenerator.cpp
@@ -1,10 +1,89 @@
 #include "TextMeshGenerator.h"
 
-UITextMesh* TextMeshGenerator::GetTextMesh(const UnicodeString& str, Font* font, int pixelSize, int lineHeight, Color32 col32, ETextAnchor anchor, ETextAlignment alignment, bool wordwrap, float preferred)
+// ����һ����ϣֵ
+static uint32_t GetStrHash(const UnicodeString& str)
 {
-	for (int i = 0; i < m_TextMeshes.size(); ++i)
-	{
-		UITextMesh* tm = m_TextMeshes[i];
+    if (str.length == 0)
+        return 0;
 
-	}
+    int len = str.length; 
+    uint32_t hash = (uint32_t)len; // seed 
+    size_t step = (len >> 5) + 1;
+    for (int l = len; l >= step; l -= step)
+    {
+        unsigned short unicode = str.str[l - 1];
+        unsigned char hicode = *((unsigned char*)&unicode);
+        unsigned char locode = *(((unsigned char*)&unicode) + 1);
+        hash = hash ^ ((hash << 5) + (hash >> 2) + hicode + locode);
+    }
+    return hash;
+}
+
+const UITextMesh* TextMeshGenerator::GetTextMesh(
+    const UnicodeString& str
+    , Font* font
+    , int pixelSize
+    , int lineHeight
+    , Color32 col32
+    , ETextAnchor anchor
+    , ETextAlignment alignment
+    , bool wordwrap
+    , float preferred
+){
+    uint32_t hash = GetStrHash(str);
+    UITextMeshList* tm = NULL;
+    bool hasHash = m_TextMeshes.count(hash);
+    if (hasHash)
+    {
+        tm = m_TextMeshes[hash];
+        while (tm)
+        {
+            UITextMesh* mesh = tm->mesh;
+            if (mesh->GetFont() != font
+                || mesh->GetPixelSize() != pixelSize
+                || mesh->GetLineHeight() != lineHeight
+                || mesh->GetAnchor() != anchor
+                || mesh->GetAlignment() != alignment
+                || mesh->GetWordwrap() != wordwrap
+                || mesh->GetPreferred() != preferred
+                || mesh->GetColor() != col32
+            ){
+                tm = tm->next;
+                continue;
+            }
+            const UnicodeString& content = mesh->GetContent();
+            if (content.length != str.length)
+            {
+                tm = tm->next;
+                continue;
+            }
+            if (memcmp(str.str, content.str, sizeof(character::Unicode) * str.length) == 0)
+            {
+                return tm->mesh;
+            }
+            tm = tm->next;
+        }
+    }
+    tm = new UITextMeshList();
+    try {
+        tm->mesh = new UITextMesh(str, font, pixelSize, lineHeight, col32, anchor, alignment, wordwrap, preferred);
+        log_info("Text", "New UITextMesh");
+    }
+    catch(TextMeshException& e) 
+    {
+        delete tm;
+        throw;
+    }
+    if (hasHash)
+    {
+        UITextMeshList* list = m_TextMeshes[hash];
+        tm->next = list; 
+        m_TextMeshes[hash] = tm;
+    }
+    else
+    {
+        tm->next = NULL;
+        m_TextMeshes.insert(std::pair<uint32_t, UITextMeshList*>(hash, tm));
+    }
+    return tm->mesh;
 }
diff --git a/Runtime/GUI/TextMeshGenerator.h b/Runtime/GUI/TextMeshGenerator.h
index dd4f1d9..815f4c4 100644
--- a/Runtime/GUI/TextMeshGenerator.h
+++ b/Runtime/GUI/TextMeshGenerator.h
@@ -3,9 +3,11 @@
 #include "UITextMesh.h"
 #include "Runtime/Utilities/IIncrementalTask.h"
 #include "Font.h"
+#include "Runtime/Debug/Log.h"
 #include <vector>
+#include <unordered_map>
 
-// collect unused text mesh gradually 
+// �𲽻��ճ���û�õ���textmesh
 class GraduallyReleaseTextMesh : public IIncrementalTask
 {
 public:
@@ -21,14 +23,18 @@ public:
 
 };
 
+struct UITextMeshList {
+    UITextMesh* mesh; 
+    UITextMeshList* next;
+};
+
 class TextMeshGenerator : public Singleton<TextMeshGenerator>
 {
 public:
-	UITextMesh* GetTextMesh(const UnicodeString& str, Font* font, int pixelSize, int lineHeight, Color32 col32, ETextAnchor anchor, ETextAlignment alignment, bool wordwrap, float preferred);
+    const UITextMesh* GetTextMesh(const UnicodeString& str, Font* font, int pixelSize, int lineHeight, Color32 col32, ETextAnchor anchor, ETextAlignment alignment, bool wordwrap, float preferred);
 
 private:
-    std::vector<UITextMesh*> m_TextMeshes;
-
+    std::unordered_map<uint32_t, UITextMeshList*> m_TextMeshes;
 };
 
 #define g_TextMeshGenerator (*TextMeshGenerator::Instance())
\ No newline at end of file
diff --git a/Runtime/GUI/UITextMesh.cpp b/Runtime/GUI/UITextMesh.cpp
index 24aff47..23c0a9c 100644
--- a/Runtime/GUI/UITextMesh.cpp
+++ b/Runtime/GUI/UITextMesh.cpp
@@ -33,7 +33,6 @@ struct TextInfo {
     int line; // ��0��ʼ
 };
 
-static unordered_map<unsigned int, vector<TextInfo>> s_TextInfos;
 
 InitializeStaticVariables([]() {
 	VertexAttributeDescriptor POSITION = VertexAttributeDescriptor(0, 2, VertexAttrFormat_Float, sizeof(TextMeshVBOLayout));
@@ -63,6 +62,20 @@ UITextMesh::UITextMesh(
     , bool wordwrap            // �Զ�����
     , float preferred          // �Զ����������С
 ){
+    m_Font = font; 
+    m_PixelSize = pixelSize;
+    m_LineHeight = lineHeight;
+    m_Color = color32; 
+    m_Alignment = alignment;
+    m_Anchor = anchor;
+    m_Wordwrap = wordwrap;
+    m_Preferred = preferred;
+    m_Content.length = str.length;
+    m_Content.str = (character::Unicode*)malloc(str.length * sizeof(character::Unicode));
+    memcpy(m_Content.str, str.str, str.length * sizeof(character::Unicode));
+
+    // ��¼�ı���atlas����
+    static unordered_map<unsigned int, vector<TextInfo>> s_TextInfos;
 	s_TextInfos.clear();
 
     // ��¼�ı�ÿ�еij���
@@ -76,9 +89,9 @@ UITextMesh::UITextMesh(
     InvokeWhenLeave([]() {
         s_LineWidths.clear();
         s_LineOffsets.clear();
+        s_TextInfos.clear();
     });
 
-    m_Font = font;
     const Vector2 atlasSize = font->GetAtlasSize();
 
     //-----------------------------------------------------------------
@@ -149,8 +162,10 @@ UITextMesh::UITextMesh(
 
     textRegion.y = (line + 1) * lineHeight;
 
-	if (s_TextInfos.size() == 0)
-		return;
+    if (s_TextInfos.size() == 0)
+    {
+        return;
+    }
 
     Vector2i textOffset;
     Vector2 halfRegion = Vector2(textRegion.x/ 2.f, textRegion.y / 2.f);
@@ -240,7 +255,7 @@ UITextMesh::UITextMesh(
     WipeGLError();
 }
 
-void UITextMesh::Draw()
+void UITextMesh::Draw() const
 {
     for (auto subText : m_VBOs)
     {
diff --git a/Runtime/GUI/UITextMesh.h b/Runtime/GUI/UITextMesh.h
index c298cb0..505b390 100644
--- a/Runtime/GUI/UITextMesh.h
+++ b/Runtime/GUI/UITextMesh.h
@@ -34,15 +34,34 @@ namespace TextHelper
 class UITextMesh
 {
 public:
-	UITextMesh(const UnicodeString& str, Font* font, int pixelSize, int lineHeight, Color32 color32 = Color32::white, ETextAnchor anchor = TextAnchor_UpperLeft, ETextAlignment alignment = TextAlignment_Left, bool wordwrap = false, float preferred = 0)/*throw TextMeshException*/;
+	void Draw() const;
 
-	~UITextMesh();
+    GET(const Font*, Font, m_Font);
+    GET(int, PixelSize, m_PixelSize);
+    GET(int, LineHeight, m_LineHeight);
+    GET(Color32, Color, m_Color);
+    GET(ETextAlignment, Alignment, m_Alignment);
+    GET(ETextAnchor, Anchor, m_Anchor);
+    GET(bool, Wordwrap, m_Wordwrap);
+    GET(float, Preferred, m_Preferred);
+    GET(const UnicodeString&, Content, m_Content);
 
-	void Draw();
+private:
+    friend class TextMeshGenerator;
 
-private: 
-	unsigned long long m_NotUniqueHash;
-	Font* m_Font;
-	std::unordered_map<int/*IndexOfAtlas*/, VertexBuffer*> m_VBOs;
+    UITextMesh(const UnicodeString& str, Font* font, int pixelSize, int lineHeight, Color32 color32 = Color32::white, ETextAnchor anchor = TextAnchor_UpperLeft, ETextAlignment alignment = TextAlignment_Left, bool wordwrap = false, float preferred = 0)/*throw TextMeshException*/;
+    ~UITextMesh();
+
+    std::unordered_map<int, VertexBuffer*> m_VBOs;
+
+	Font*          m_Font;
+    UnicodeString  m_Content;
+    int            m_PixelSize; 
+    int            m_LineHeight;
+    Color32        m_Color; 
+    ETextAlignment m_Alignment; 
+    ETextAnchor    m_Anchor;
+    bool           m_Wordwrap; 
+    float          m_Preferred;
 	
 };
\ No newline at end of file
diff --git a/Runtime/Graphics/Color.h b/Runtime/Graphics/Color.h
index 41ca2a4..043590b 100644
--- a/Runtime/Graphics/Color.h
+++ b/Runtime/Graphics/Color.h
@@ -40,6 +40,12 @@ namespace Internal
             this->b = b;
             this->a = a;
         }
+
+        bool operator !=(const Color32& col)
+        {
+            return !(r == col.r && g == col.g && b == col.b && a == col.a);
+        }
+
 		unsigned char r, g, b, a;
 
         static const Color32 white;
diff --git a/Runtime/Scripting/GUI/Font.bind.cpp b/Runtime/Scripting/GUI/Font.bind.cpp
index 7d7e3f2..0570df0 100644
--- a/Runtime/Scripting/GUI/Font.bind.cpp
+++ b/Runtime/Scripting/GUI/Font.bind.cpp
@@ -7,6 +7,8 @@
 #include "Runtime/Utilities/StaticInitiator.h"
 #include "Runtime/GUI/UITextMesh.h"
 #include "Runtime/Math/Math.h"
+#include "Runtime/GUI/TextMeshGenerator.h"
+#include "Runtime/Utilities/AutoInvoke.h"
 
 static std::vector<character::Unicode>* s_Codepoints;
 
@@ -102,6 +104,10 @@ LUA_BIND_IMPL_METHOD(Font, _GetCharacters)
     int encoding = state.GetValue<int>(6, EEncoding::Encoding_UTF8);
 
     s_Codepoints->clear();
+    InvokeWhenLeave([]() {
+        s_Codepoints->clear();
+    });
+
     if (encoding == EEncoding::Encoding_UTF8) 
     {
         while (*buf != 0) {
@@ -137,7 +143,7 @@ LUA_BIND_IMPL_METHOD(Font, _GetCharacters)
 
     WipeGLError();
 
-    UITextMesh* tm = new UITextMesh(str, self, size, size + 3, Color32::white, TextAnchor_UpperLeft, TextAlignment_Left, wordwrap, preferred);
+    const UITextMesh* tm = g_TextMeshGenerator.GetTextMesh(str, self, size, size + 3, Color32::white, TextAnchor_UpperLeft, TextAlignment_Left, wordwrap, preferred);
     tm->Draw();
 
     return 0;
diff --git a/Runtime/Utilities/UtilMacros.h b/Runtime/Utilities/UtilMacros.h
index 1941d7f..f48be5c 100644
--- a/Runtime/Utilities/UtilMacros.h
+++ b/Runtime/Utilities/UtilMacros.h
@@ -13,4 +13,7 @@
 
 #define Mask(v)   (1 << v)
 
+#define cast(T, v) \
+((T)(v))
+
 #endif
\ No newline at end of file
-- 
cgit v1.1-26-g67d0