From 26f05c6e3dcac9995345fb5a2b031be7e3ea79e9 Mon Sep 17 00:00:00 2001
From: chai <chaifix@163.com>
Date: Sat, 30 Oct 2021 22:59:42 +0800
Subject: *TextGenerator

---
 Data/Editor.exe                              | Bin 0 -> 2385408 bytes
 Data/Resources/Font/Deng.ttf                 | Bin 0 -> 16093132 bytes
 Data/Scripts/Editor/AssetBrowser.lua         |   9 +-
 Data/Scripts/EditorApplication.lua           |   2 +
 Editor/EditorMain.cpp                        |  28 +++-
 Editor/GUI/ContainerWindow.cpp               |  19 ++-
 Editor/GUI/EditorWindows.h                   |   4 -
 Editor/GUI/GUIWindow.cpp                     |  18 +--
 Editor/Graphics/Graphics.cpp                 |   2 +
 Editor/Graphics/Graphics.h                   |   2 +
 Runtime/Common/DataBuffer.h                  |   2 +-
 Runtime/FileSystem/ImageJobs.cpp             |   4 +-
 Runtime/GUI/TextGenerator.cpp                | 205 +++++++++++++++++++++++++--
 Runtime/GUI/TextGenerator.h                  |  89 ++++++++++--
 Runtime/Graphics/GfxDevice.cpp               |   6 +-
 Runtime/Graphics/ImageData.h                 |  38 ++---
 Runtime/Graphics/Texture.cpp                 | 118 ++++++++++++++-
 Runtime/Graphics/Texture.h                   |   3 +
 Runtime/Math/Math.h                          |   4 +
 Runtime/Math/Rect.h                          |   2 +-
 Runtime/Scripting/Resource/Resource.bind.cpp |   4 +-
 21 files changed, 481 insertions(+), 78 deletions(-)
 create mode 100644 Data/Editor.exe
 create mode 100644 Data/Resources/Font/Deng.ttf

diff --git a/Data/Editor.exe b/Data/Editor.exe
new file mode 100644
index 0000000..e59406e
Binary files /dev/null and b/Data/Editor.exe differ
diff --git a/Data/Resources/Font/Deng.ttf b/Data/Resources/Font/Deng.ttf
new file mode 100644
index 0000000..7438a2a
Binary files /dev/null and b/Data/Resources/Font/Deng.ttf differ
diff --git a/Data/Scripts/Editor/AssetBrowser.lua b/Data/Scripts/Editor/AssetBrowser.lua
index a36cda2..68f0483 100644
--- a/Data/Scripts/Editor/AssetBrowser.lua
+++ b/Data/Scripts/Editor/AssetBrowser.lua
@@ -42,7 +42,11 @@ out vec4 FragColor;
 
 void main()
 {
-	FragColor = texture(uiTex, uv);
+    vec4 sampled = vec4(texture(uiTex, uv).r, 0, 0, 1.0);
+    FragColor = sampled;
+//	FragColor = texture(uiTex, uv);
+//	FragColor.rgb = vec3(1,0,0);
+//	FragColor.a = 1;
 }
 FSH_END
 
@@ -52,6 +56,7 @@ local tex
 
 AssetBrowser.OnGUI = function(self)
 
+
 	if tex == nil then 
 		tex = Engine.Resource.LoadTexture("./Resources/Images/brickwall.jpg")
 	end
@@ -76,7 +81,7 @@ AssetBrowser.OnGUI = function(self)
 
 	Engine.Rendering.UseShader(shader)
 	Engine.Rendering.SetMatrix44("mvp", ortho)
-	Engine.Rendering.SetTexture("tex", tex)
+	Engine.Rendering.SetTexture("uiTex", tex)
 	Engine.Rendering.DrawUIQuad({10, 30, 300, 300})
 
 	Engine.Rendering.ResetUniformState()
diff --git a/Data/Scripts/EditorApplication.lua b/Data/Scripts/EditorApplication.lua
index 75749df..e9dbc32 100644
--- a/Data/Scripts/EditorApplication.lua
+++ b/Data/Scripts/EditorApplication.lua
@@ -111,6 +111,8 @@ local fsh = [[
 	}
 ]]
 
+BeforeMainLoop()
+	
 while true do
 
 	app:OnStep()
diff --git a/Editor/EditorMain.cpp b/Editor/EditorMain.cpp
index 69c1c1a..e31da28 100644
--- a/Editor/EditorMain.cpp
+++ b/Editor/EditorMain.cpp
@@ -9,6 +9,8 @@
 #include "Editor/Win/Win.h"
 #include "Runtime/Threading/Thread.h"
 
+#include "Runtime/GUI/TextGenerator.h"
+
 using namespace LuaBind;
 
 void ErrorHandle(cc8* msg)
@@ -16,6 +18,27 @@ void ErrorHandle(cc8* msg)
 	log_error(std::string("[Lua] ") + msg);
 }
 
+void TestFont()
+{
+	TextGeneratingSettings setting;
+	setting.margin = 5;
+	setting.padding = 3;
+	setting.atlasSize = Internal::Vector2(256, 256);
+	TextGenerator::Instance()->Setup(setting);
+	TextGenerator::Instance()->RenderCharacter(L'��', 14);
+	TextGenerator::Instance()->RenderCharacter(L'��', 14);
+	TextGenerator::Instance()->RenderCharacter(L'��', 14);
+	TextGenerator::Instance()->RenderCharacter(L'��', 14);
+	TextGenerator::Instance()->RenderCharacter(L'��', 14);
+	TextGenerator::Instance()->RenderCharacter(L'��', 14);
+}
+
+int BeforeMainLoop(lua_State* L)
+{
+	TestFont();
+	return 0;
+}
+
 void InitLuaState(LuaBind::VM& vm)
 {
 	vm.Setup();
@@ -35,6 +58,9 @@ void InitLuaState(LuaBind::VM& vm)
 	Win::SetDllSearchDirectory(workingDir);
 
     LuaBind::State state = vm.GetMainState();
+	state.PushGlobalNamespace();
+	state.RegisterMethod("BeforeMainLoop", BeforeMainLoop);
+
     state.DoFile("./boot.lua");
 }
 
@@ -50,4 +76,4 @@ int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrev, LPSTR szCmdLine, int sw)
 	InitLuaState(vm);
 
 	return 0;
-}
\ No newline at end of file
+}
diff --git a/Editor/GUI/ContainerWindow.cpp b/Editor/GUI/ContainerWindow.cpp
index 62c6cb7..01bb1e9 100644
--- a/Editor/GUI/ContainerWindow.cpp
+++ b/Editor/GUI/ContainerWindow.cpp
@@ -196,8 +196,8 @@ void ContainerWindow::DoPaint()
 void ContainerWindow::SetAsRenderContext()
 {
 	Assert(m_DC != NULL);
-	Assert(m_RC != NULL);
-	Assert(wglMakeCurrent(m_DC, m_RC));
+	Assert(g_GLRC != NULL);
+	Assert(wglMakeCurrent(m_DC, g_GLRC));
 	RECT rect;
 	GetWindowRect(m_Window, &rect);
 	glViewport(0, 0, rect.right - rect.left, rect.bottom - rect.top);
@@ -256,16 +256,15 @@ bool ContainerWindow::SetRenderContext()
 	int pf = 0;
 	DescribePixelFormat(m_DC, pf, sizeof(PIXELFORMATDESCRIPTOR), &pfd);
 
-	if (!(m_RC = wglCreateContext(m_DC)))               // Are We Able To Get A Rendering Context?
-	{
-		MessageBox(NULL, "Can't Create A GL Rendering Context.", "ERROR", MB_OK | MB_ICONEXCLAMATION);
-		return FALSE;                               // Return FALSE
-	}
-
-    if (m_RC && !g_IsGLInitialized)
+    if (g_GLRC == NULL || !g_IsGLInitialized)
     {
+		if (!(g_GLRC = wglCreateContext(m_DC)))               // Are We Able To Get A Rendering Context?
+		{
+			MessageBox(NULL, "Can't Create A GL Rendering Context.", "ERROR", MB_OK | MB_ICONEXCLAMATION);
+			return FALSE;                               // Return FALSE
+		}
         log_info("Initialize OpenGL");
-        wglMakeCurrent(m_DC, m_RC);
+        wglMakeCurrent(m_DC, g_GLRC);
         if (!gladLoadGL()) {
             log_error("��ʼ��GL����");
         }
diff --git a/Editor/GUI/EditorWindows.h b/Editor/GUI/EditorWindows.h
index 79e047c..e1ad89a 100644
--- a/Editor/GUI/EditorWindows.h
+++ b/Editor/GUI/EditorWindows.h
@@ -67,7 +67,6 @@ public:
 
 	GET(HWND, WindowHandle, m_Window);
 	GET(HDC, DC, m_DC);
-	GET(HGLRC, RC, m_RC);
 
 	void OnRectChanged();
 	void OnActivateApplication(bool active);
@@ -79,7 +78,6 @@ private:
 
 	HWND m_Window;
 	HDC m_DC;
-	HGLRC m_RC;
 	POINT m_Size;
     ShowMode m_ShowMode; // ��������
     bool  m_IsClosing;
@@ -149,7 +147,6 @@ public:
 
 	GET_SET(std::string, Name, m_Name);
 	GET(HDC, DC, m_DC);
-	GET(HGLRC, RC, m_RC);
 
 private:
 	void ProcessEventMessages(UINT message, WPARAM wParam, LPARAM lParam);
@@ -160,7 +157,6 @@ private:
 	ContainerWindow* m_ContainerWindow;
 	HWND m_Handle;
 	HDC m_DC;
-	HGLRC m_RC;
 
 	std::vector<LuaBind::MemberRef> m_EditorWindows;
 
diff --git a/Editor/GUI/GUIWindow.cpp b/Editor/GUI/GUIWindow.cpp
index fddc68d..eb44647 100644
--- a/Editor/GUI/GUIWindow.cpp
+++ b/Editor/GUI/GUIWindow.cpp
@@ -293,21 +293,6 @@ bool GUIWindow::SetRenderContext()
 	int pf = 0;
 	DescribePixelFormat(m_DC, pf, sizeof(PIXELFORMATDESCRIPTOR), &pfd);
 
-	if (!(m_RC = wglCreateContext(m_DC)))               // Are We Able To Get A Rendering Context?
-	{
-		MessageBox(NULL, "Can't Create A GL Rendering Context.", "ERROR", MB_OK | MB_ICONEXCLAMATION);
-		return FALSE;                               // Return FALSE
-	}
-
-    if (m_RC && !g_IsGLInitialized)
-    {
-        log_info("Initialize OpenGL");
-        wglMakeCurrent(m_DC, m_RC);
-        if (!gladLoadGL()) {
-            log_error("��ʼ��GL����");
-        }
-        g_IsGLInitialized = true;
-    }
 	return true;
 }
 
@@ -345,8 +330,7 @@ void GUIWindow::SetPosition(Internal::Rect position)
 void GUIWindow::SetAsRenderContext()
 {
 	Assert(m_DC != NULL);
-	Assert(m_RC != NULL);
-	Assert(wglMakeCurrent(m_DC, m_RC));
+	Assert(wglMakeCurrent(m_DC, g_GLRC));
 	RECT rect;
 	GetWindowRect(m_Handle, &rect);
 	glViewport(0, 0, rect.right - rect.left, rect.bottom - rect.top);
diff --git a/Editor/Graphics/Graphics.cpp b/Editor/Graphics/Graphics.cpp
index af48d75..4c9465f 100644
--- a/Editor/Graphics/Graphics.cpp
+++ b/Editor/Graphics/Graphics.cpp
@@ -1,3 +1,5 @@
 #include "Graphics.h"
 
 bool g_IsGLInitialized = false;
+
+HGLRC g_GLRC = NULL;
\ No newline at end of file
diff --git a/Editor/Graphics/Graphics.h b/Editor/Graphics/Graphics.h
index ad27ede..f32246a 100644
--- a/Editor/Graphics/Graphics.h
+++ b/Editor/Graphics/Graphics.h
@@ -1,3 +1,5 @@
 #pragma once
+#include <windows.h>
 
 extern bool g_IsGLInitialized;
+extern HGLRC g_GLRC;
\ No newline at end of file
diff --git a/Runtime/Common/DataBuffer.h b/Runtime/Common/DataBuffer.h
index 74d2b02..7004937 100644
--- a/Runtime/Common/DataBuffer.h
+++ b/Runtime/Common/DataBuffer.h
@@ -17,7 +17,7 @@ public:
         delete data;
     }
 
-	char* data;
+	unsigned char* data;
 	int   length;
 
 private:
diff --git a/Runtime/FileSystem/ImageJobs.cpp b/Runtime/FileSystem/ImageJobs.cpp
index 84e4ff3..1d836d2 100644
--- a/Runtime/FileSystem/ImageJobs.cpp
+++ b/Runtime/FileSystem/ImageJobs.cpp
@@ -41,8 +41,8 @@ void ReadImageFileJob::Dispacth(void* param)
 	bridge.pixels = NULL;
 	imgData->width = bridge.width;
 	imgData->height = bridge.height;
-	imgData->format = ImageData::EPixelFormat::RGB;
-	imgData->type = ImageData::EPixelElementType::UNSIGNED_BYTE;
+	imgData->format = EPixelFormat::PixelFormat_RGB;
+	imgData->type = EPixelElementType::PixelType_UNSIGNED_BYTE;
 
 	callback.PushRef(state);
 	imgData->PushUserdata(state);
diff --git a/Runtime/GUI/TextGenerator.cpp b/Runtime/GUI/TextGenerator.cpp
index 6841c4e..a518772 100644
--- a/Runtime/GUI/TextGenerator.cpp
+++ b/Runtime/GUI/TextGenerator.cpp
@@ -1,19 +1,206 @@
 #include "freetype.h"
 #include "TextGenerator.h"
 #include "../Math/Math.h"
+#include "Runtime/Debug/Log.h"
+#include "Runtime/Utilities/Assert.h"
+#include "Runtime/Graphics/ImageData.h"
 
 using namespace character;
 
+//https://unicode-table.com/en/#cjk-unified-ideographs-extension-a
 //https://learnopengl.com/In-Practice/Text-Rendering
+//https://www.zhihu.com/question/294660079
+//https://baike.baidu.com/item/%E5%9F%BA%E6%9C%AC%E5%A4%9A%E6%96%87%E7%A7%8D%E5%B9%B3%E9%9D%A2/10788078
+//https://stackoverflow.com/questions/27331819/whats-the-difference-between-a-character-a-code-point-a-glyph-and-a-grapheme
 
-struct Character {
-	unsigned int        textureID;  // ID handle of the glyph texture
-	Internal::Vector2   size;       // Size of glyph
-	Internal::Vector2   bearing;    // Offset from baseline to left/top of glyph
-	unsigned int        advance;    // Offset to advance to next glyph
-};
+void TextGenerator::Setup(TextGeneratingSettings settings)
+{
+	m_AtlasMargin = settings.margin;
+	m_GlyphPadding = settings.padding;
+	m_AtlasSize = settings.atlasSize;
+
+	if (FT_Init_FreeType(&m_FTLibrary))
+	{
+		return;
+	}
+
+	if (FT_New_Face(m_FTLibrary, "Resources/Font/Deng.ttf", 0, &m_FTFace))
+	{
+		return;
+	}
+}
+
+character::Hash TextGenerator::GetHash(Codepoint codepoint, int pixelSize)
+{
+	character::Hash hash;
+	hash.codepoint = codepoint;
+	hash.size = pixelSize;
+	return hash;
+}
+
+Character TextGenerator::GetCharacter(character::Codepoint codepoint, int pixelSize)
+{
+	character::Hash hash = GetHash(codepoint, pixelSize);
+	auto iter = m_Characters.find(hash);
+	if (iter == m_Characters.end())
+	{
+		RenderCharacter(codepoint, pixelSize);
+		iter = m_Characters.find(hash);
+	}
+	Assert(iter != m_Characters.end());
+	return iter->second;
+}
+
+void TextGenerator::RenderCharacter(character::Codepoint codepoint, int pixelSize)
+{
+	character::Hash hash = GetHash(codepoint, pixelSize);
+//	if (m_Characters.count(hash) != 0)
+//		return; 
+	FT_Set_Pixel_Sizes(m_FTFace, 0, pixelSize);
+	if (FT_Load_Char(m_FTFace, codepoint, FT_LOAD_RENDER))
+	{
+		return;
+	}
+
+	int w = m_FTFace->glyph->bitmap.width;
+	int h = m_FTFace->glyph->bitmap.rows;
+
+	TextHelper::print_glyph(m_FTFace->glyph->bitmap.buffer, w, h);
+
+	GlyphAtals* atlas = RequestAtlas(pixelSize, Internal::Vector2(w, h));
+	Assert(atlas);
+
+	Internal::Rect rect = GetRenderChartAndMove(atlas, Internal::Vector2(w, h));
+
+	try
+	{
+		atlas->altas->UpdateSubImage(rect, EPixelFormat::PixelFormat_R, EPixelElementType::PixelType_UNSIGNED_BYTE, m_FTFace->glyph->bitmap.buffer);
+	}
+	catch (TextureException& e)
+	{
+		std::string error = e.what();
+		error = "Render Character Error: " + error;
+		log_error(e.what());
+		return;
+	}
+
+	Character character;
+	character.atlas = atlas->index;
+	character.position = rect;
+	character.bearing = Internal::Vector2(m_FTFace->glyph->bitmap_left, m_FTFace->glyph->bitmap_top);
+	character.advance = m_FTFace->glyph->advance.x;
+
+	m_Characters.insert(std::pair<character::Hash, Character>(hash, character));
+}
+
+GlyphAtals* TextGenerator::GetGlyphAtlas(int index)
+{
+	if (index >= m_Atlases.size())
+		return NULL;
+	return &m_Atlases[index];
+}
+
+Internal::Rect TextGenerator::GetRenderChartAndMove(GlyphAtals* atlas, Internal::Vector2 preferSize)
+{
+	Internal::Rect rect;
+	Internal::Vector2 space;
+	space.x = atlas->width - m_AtlasMargin * 2 - m_GlyphPadding - atlas->cursor.x;
+	space.y = atlas->height - m_AtlasMargin * 2 - m_GlyphPadding - atlas->cursor.y;
+	if (space.x > preferSize.x && space.y > preferSize.y)
+	{
+		rect.x = atlas->cursor.x;
+		rect.y = atlas->cursor.y;
+		rect.width = preferSize.x;
+		rect.height = preferSize.y;
+		atlas->cursor.x += rect.width;
+		atlas->rowHeight = max(atlas->rowHeight, preferSize.y);
+	}
+	else if (space.y - atlas->rowHeight > preferSize.y)
+	{
+		rect.x = m_AtlasMargin;
+		rect.y = atlas->cursor.y + m_GlyphPadding + atlas->rowHeight;
+		rect.width = preferSize.x;
+		rect.height = preferSize.y;
+		atlas->cursor.x = m_AtlasMargin;
+		atlas->cursor.y += atlas->rowHeight;
+		atlas->rowHeight = rect.height;
+	}
+	else
+	{
+		Assert(false);
+	}
+	return rect;
+}
+
+GlyphAtals* TextGenerator::RequestAtlas(int pixelSize, Internal::Vector2 preferSize)
+{
+	GlyphAtals* atlas = NULL;
+	auto iter = m_AtlasCache.find(pixelSize);
+	if (iter == m_AtlasCache.end() || !HasEnoughSpace(iter->second, preferSize))
+	{
+		Texture* tex = CreateAtlas();
+		GlyphAtals newAtlas = GlyphAtals();
+		newAtlas.altas = tex;
+		newAtlas.width = m_AtlasSize.x;
+		newAtlas.height = m_AtlasSize.y;
+		newAtlas.index = m_Atlases.size();
+		newAtlas.cursor = Internal::Vector2(m_AtlasMargin, m_AtlasMargin);
+
+		m_Atlases.push_back(newAtlas);
+		atlas = &m_Atlases[m_Atlases.size() - 1];
+
+		if (iter != m_AtlasCache.end())
+			m_AtlasCache.erase(pixelSize);
+		m_AtlasCache.insert(std::pair<int, GlyphAtals*>(pixelSize, atlas));
+	}
+	else 
+	{
+		atlas = iter->second;
+	}
+	Assert(atlas);
+	return atlas;
+}
+
+Texture* TextGenerator::CreateAtlas()
+{
+	TextureSetting setting; 
+	setting.filterMode = ETextureFilterMode::Linear;
+	setting.wrapMode = ETextureWrapMode::Clamp;
+	setting.format = ETextureFormat::R8;
+	setting.type = ETextureType::TEX_2D;
+	setting.keepImageData = false;
+	Texture* tex = new Texture(setting, m_AtlasSize.x, m_AtlasSize.y);
+	return tex;
+}
+
+bool TextGenerator::HasEnoughSpace(GlyphAtals* atlas, Internal::Vector2 preferSize)
+{
+	if (atlas == NULL)
+		return false;
+	Internal::Vector2 space;
+	space.x = atlas->width - m_AtlasMargin * 2 - m_GlyphPadding - atlas->cursor.x;
+	space.y = atlas->height - m_AtlasMargin * 2 - m_GlyphPadding - atlas->cursor.y;
+	if (space.x > preferSize.x && space.y > preferSize.y)
+		return true;
+	if (space.y - atlas->rowHeight > preferSize.y)
+		return true;
+	return false;
+}
+
+Character GetCharacter(character::Codepoint Codepoint, int pixelSize)
+{
+	return Character();
+}
 
-hash TextGenerator::GetCharacterHash(unicode unicode, int pixelSize)
+void TextHelper::print_glyph(unsigned char* glyph, int width, int height)
 {
-	
-}
\ No newline at end of file
+	for (int r = 0; r < height; ++r)
+	{
+		for (int c = 0; c < width; ++c)
+		{
+			unsigned char ch = glyph[c + r * width];
+			printf("%c", ch == 0 ? ' ' : '+');
+		}
+		printf("\n");
+	}
+}
diff --git a/Runtime/GUI/TextGenerator.h b/Runtime/GUI/TextGenerator.h
index eacc99c..1065acf 100644
--- a/Runtime/GUI/TextGenerator.h
+++ b/Runtime/GUI/TextGenerator.h
@@ -1,32 +1,105 @@
 #pragma once 
 
 #include "Runtime/Utilities/Singleton.h"
+#include "Runtime/Graphics/Texture.h"
+#include "freetype.h"
+
 #include <string>
 #include <unordered_map>
+#include <vector>
 
 //https://learnopengl.com/In-Practice/Text-Rendering
 
 struct Character {
-	unsigned int        textureID;  // ID handle of the glyph texture
-	Internal::Vector2   size;       // Size of glyph
-	Internal::Vector2   bearing;    // Offset from baseline to left/top of glyph
-	unsigned int        advance;    // Offset to advance to next glyph
+	unsigned int      atlas;    // atlas����
+	Internal::Rect    position; // ��altas����
+	Internal::Vector2 bearing;  // ���Ͻ������ԭ���ƫ��
+	unsigned int      advance;  // �ܿ��������˼��
 };
 
 namespace character
 {
-	typedef wchar_t unicode;
-	typedef unsigned int hash;
+	typedef unsigned short Codepoint; // unicode Codepoint��BMP��U+0000��U+FFFF)
+
+	union Hash {
+		unsigned int hashCode;
+		struct {
+			Codepoint codepoint;
+			unsigned short size;//�����С
+		};
+		bool operator==(const Hash &other) const
+		{
+			return codepoint == other.codepoint && size == other.size;
+		}
+	};
+}
+
+namespace std
+{
+	template <>
+	struct hash<character::Hash>
+	{
+		std::size_t operator()(const character::Hash& k) const
+		{
+			return k.hashCode;
+		}
+	};
 }
 
+struct GlyphAtals
+{
+	int index;
+	Texture* altas;           // ��ͼ
+	int width, height;        // �ߴ�
+	Internal::Vector2 cursor; // �α꣬�����Ͻǣ�0,0����ʼ
+	int rowHeight;            // ��ǰ�еĸ߶�
+};
+
+struct TextGeneratingSettings
+{
+	Internal::Vector2 atlasSize; // atlas�ijߴ�
+	int margin;  // atlas�ı߽�
+	int padding; // glyph�໥֮��ļ�࣬��ֹ������ʱ��Խ��
+};
+
 class TextGenerator : public Singleton<TextGenerator>
 {
 public:
+	void Setup(TextGeneratingSettings settings);
 
+	Character GetCharacter(character::Codepoint codepoint, int pixelSize);
+	void RenderCharacter(character::Codepoint codepoint, int pixelSize);
+	GlyphAtals* GetGlyphAtlas(int index);
 
 private: 
-	std::unordered_map<character::hash, Character> m_Characters;
 
-	character::hash GetCharacterHash(character::unicode unicode, int pixelSize);
+	Texture* CreateAtlas();
+	GlyphAtals* RequestAtlas(int pixelSize, Internal::Vector2 preferSize);
+
+	Internal::Rect GetRenderChartAndMove(GlyphAtals* atlas, Internal::Vector2 preferSize);
+	bool HasEnoughSpace(GlyphAtals* atlas, Internal::Vector2 preferSize);
+
+	std::unordered_map<character::Hash, Character> m_Characters; // ��Ⱦ�������
+
+	std::vector<GlyphAtals> m_Atlases; // ��ǰ���е�atlas
+	std::unordered_map<int, GlyphAtals*> m_AtlasCache;  // �����ҵ����õ�atlas
+
+	int m_AtlasMargin;
+	int m_GlyphPadding;
+	Internal::Vector2 m_AtlasSize;
+
+	FT_Library m_FTLibrary;
+	FT_Face m_FTFace;
+
+	character::Hash GetHash(character::Codepoint Codepoint, int pixelSize);
 
 };
+
+#define g_TextGenerator (*TextGenerator::Instance())
+
+namespace TextHelper
+{
+
+	void print_glyph(unsigned char* glyph, int width, int height);
+
+}
diff --git a/Runtime/Graphics/GfxDevice.cpp b/Runtime/Graphics/GfxDevice.cpp
index d30a60a..f318487 100644
--- a/Runtime/Graphics/GfxDevice.cpp
+++ b/Runtime/Graphics/GfxDevice.cpp
@@ -80,6 +80,9 @@ void GfxDevice::UseShader(LuaBind::State& state, Shader* shader, int idx)
 
     m_Shader.shader = shader;
     m_Shader.ref.SetRef(state, idx);
+
+	glEnable(GL_BLEND);
+	glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
 }
 
 void GfxDevice::UnuseShader()
@@ -135,7 +138,8 @@ void GfxDevice::SetUniformTexture(const char* name, Texture* texture)
     int texUnit = s_TextureUnitBucket.back();
     s_TextureUnitBucket.pop_back();
     glActiveTexture(GL_TEXTURE0 + texUnit);
-    glBindTexture(GL_TEXTURE_2D, texture->GetGpuID());
+	//glBindTexture(GL_TEXTURE_2D, texture->GetGpuID());
+	glBindTexture(GL_TEXTURE_2D, 2);
 
     GLint loc = glGetUniformLocation(m_Shader.GetID(), name);
     glUniform1i(loc, texUnit);
diff --git a/Runtime/Graphics/ImageData.h b/Runtime/Graphics/ImageData.h
index 7bf0335..fe26776 100644
--- a/Runtime/Graphics/ImageData.h
+++ b/Runtime/Graphics/ImageData.h
@@ -5,29 +5,29 @@
 #include "Runtime/Threading/Job.h"
 #include "Runtime/Lua/LuaHelper.h"
 
+enum EPixelFormat
+{
+	PixelFormat_RGBA,
+	PixelFormat_RGB,
+	PixelFormat_R,
+	PixelFormat_RG,
+	PixelFormat_BGR,
+	PixelFormat_BGRA
+};
+
+enum EPixelElementType
+{
+	PixelType_UNSIGNED_BYTE,
+	PixelType_UNSIGNED_INT,
+	PixelType_BYTE,
+	PixelType_INT,
+	PixelType_FLOAT,
+};
+
 // ͼƬ��������
 class ImageData : public LuaBind::NativeClass<ImageData>
 {
 public:
-	enum EPixelFormat
-	{
-        RGBA, 
-        RGB, 
-        R, 
-        RG,
-        BGR,
-        BGRA
-	};
-
-    enum EPixelElementType
-    {
-        UNSIGNED_BYTE,
-        UNSIGNED_INT,
-        BYTE,
-        INT, 
-        FLOAT, 
-    };
-
     ImageData(LuaBind::VM* vm) 
         : LuaBind::NativeClass<ImageData>(vm) 
     {
diff --git a/Runtime/Graphics/Texture.cpp b/Runtime/Graphics/Texture.cpp
index 6b682e9..f92c094 100644
--- a/Runtime/Graphics/Texture.cpp
+++ b/Runtime/Graphics/Texture.cpp
@@ -3,7 +3,6 @@
 
 using namespace LuaBind;
 
-
 Texture::Texture(TextureSetting setting, ImageData* imgData)
 	: NativeClass<Texture>()
 {
@@ -94,7 +93,124 @@ void Texture::Init(TextureSetting setting, ImageData* imgData)
 	);
 }
 
+Texture::Texture(TextureSetting setting, int w, int h)
+	: NativeClass<Texture>()
+{
+	m_KeepPixelData = false;
+
+	m_Width = w;
+	m_Height = h;
+	m_Type = setting.type;
+	m_Format = setting.format;
+	m_WrapMode = setting.wrapMode;
+	m_FilterMode = setting.filterMode;
+	m_KeepPixelData = setting.keepImageData;
+
+	glGenTextures(1, &m_GPUID);
+	glBindTexture(GL_TEXTURE_2D, m_GPUID);
+
+	CheckGLError(
+		glDeleteTextures(1, &m_GPUID);
+		glBindTexture(GL_TEXTURE_2D, 0);
+		throw TextureException(error);
+	);
+
+	switch (m_WrapMode) {
+	case ETextureWrapMode::Clamp:
+		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
+		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
+		break;
+	case ETextureWrapMode::Repeat:
+		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
+		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
+		break;
+	case ETextureWrapMode::Mirror:
+		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_MIRRORED_REPEAT);
+		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_MIRRORED_REPEAT);
+		break;
+	default:
+		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
+		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
+		break;
+	}
+
+	CheckGLError(
+		glDeleteTextures(1, &m_GPUID);
+		glBindTexture(GL_TEXTURE_2D, 0);
+		throw TextureException(error);
+	);
+
+	switch (m_FilterMode) {
+		case ETextureFilterMode::Linear:
+			glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+			glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+			break;
+		case ETextureFilterMode::Nearest:
+			glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+			glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+			break;
+		default:
+			glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+			glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+			break;
+	}
+	GLenum internalFormat = GL_RGB;
+	if (m_Format == ETextureFormat::R8)
+	{
+		internalFormat = GL_RED;
+	}
+
+	glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
+
+	glTexImage2D(GL_TEXTURE_2D, 0, internalFormat, w, h, 0, GL_RED, GL_UNSIGNED_BYTE, NULL);
+
+	CheckGLError(
+		glDeleteTextures(1, &m_GPUID);
+		glBindTexture(GL_TEXTURE_2D, 0);
+		throw TextureException(error);
+	);
+}
+
 Texture::~Texture()
 {
     glDeleteTextures(1, &m_GPUID);
+}
+
+void Texture::UpdateSubImage(Internal::Rect rect, int format, int type, const void* data)
+{
+	glBindTexture(GL_TEXTURE_2D, m_GPUID);
+
+	CheckGLError(
+		glBindTexture(GL_TEXTURE_2D, 0);
+		throw TextureException(error);
+	);
+
+	GLenum fmt = GL_RED; 
+	switch (format)
+	{
+		case EPixelFormat::PixelFormat_BGR: fmt = GL_BGR; break;
+		case EPixelFormat::PixelFormat_BGRA:fmt = GL_BGRA; break;
+		case EPixelFormat::PixelFormat_R:  fmt = GL_RED; break;
+		case EPixelFormat::PixelFormat_RG: fmt = GL_RG; break;
+		case EPixelFormat::PixelFormat_RGB: fmt = GL_RGB; break;
+		case EPixelFormat::PixelFormat_RGBA: fmt = GL_RGBA; break;
+	}
+	GLenum t = GL_UNSIGNED_BYTE;
+	switch (type) 
+	{
+		case EPixelElementType::PixelType_UNSIGNED_BYTE: t = GL_UNSIGNED_BYTE; break;
+		case EPixelElementType::PixelType_UNSIGNED_INT: t = GL_UNSIGNED_INT; break;
+		case EPixelElementType::PixelType_BYTE: t = GL_BYTE; break;
+		case EPixelElementType::PixelType_INT: t = GL_INT; break;
+		case EPixelElementType::PixelType_FLOAT: t = GL_FLOAT; break;
+	}
+
+	glTexSubImage2D(GL_TEXTURE_2D, 0, rect.x, rect.y, rect.width, rect.height, fmt, t, data);
+
+	CheckGLError(
+		glBindTexture(GL_TEXTURE_2D, 0);
+		throw TextureException(error);
+	);
+
+	glBindTexture(GL_TEXTURE_2D, 0);
 }
\ No newline at end of file
diff --git a/Runtime/Graphics/Texture.h b/Runtime/Graphics/Texture.h
index d02634c..6ead2fb 100644
--- a/Runtime/Graphics/Texture.h
+++ b/Runtime/Graphics/Texture.h
@@ -61,10 +61,13 @@ public:
 class Texture : public LuaBind::NativeClass<Texture>
 {
 public: 
+	Texture(TextureSetting setting, int width, int height)/*throw TextureException*/; // ����ͼ
 	Texture(TextureSetting setting, ImageData* imgData)/*throw TextureException*/;
 	Texture(LuaBind::VM* vm, TextureSetting setting, ImageData* imgData)/*throw TextureException*/;
 	~Texture();
 
+	void UpdateSubImage(Internal::Rect rect, int format, int type, const void* data);
+
 	GET(int, Width, m_Width);
 	GET(int, Height, m_Height);
 
diff --git a/Runtime/Math/Math.h b/Runtime/Math/Math.h
index 370b91c..7f61544 100644
--- a/Runtime/Math/Math.h
+++ b/Runtime/Math/Math.h
@@ -5,3 +5,7 @@
 #include "Vector4.h"
 #include "Matrix44.h"
 #include "FloatConversion.h"
+#include "Rect.h"
+
+#define max(a, b)\
+(a)>(b)?(a):(b)
diff --git a/Runtime/Math/Rect.h b/Runtime/Math/Rect.h
index 80170d6..8e7dae6 100644
--- a/Runtime/Math/Rect.h
+++ b/Runtime/Math/Rect.h
@@ -4,6 +4,6 @@ namespace Internal
 {
     struct Rect
     {
-        int x, y, width, height;
+        float x, y, width, height;
     };
 }
\ No newline at end of file
diff --git a/Runtime/Scripting/Resource/Resource.bind.cpp b/Runtime/Scripting/Resource/Resource.bind.cpp
index 6f9c0bb..379d88d 100644
--- a/Runtime/Scripting/Resource/Resource.bind.cpp
+++ b/Runtime/Scripting/Resource/Resource.bind.cpp
@@ -32,8 +32,8 @@ int LoadImageData(lua_State* L)
 	ImageData* data = new ImageData(state.GetVM());
 	int channels;
 	data->pixels = stbi_load(path, &data->width, &data->height, &channels, 0);
-	data->format = ImageData::EPixelFormat::RGB;
-	data->type = ImageData::EPixelElementType::UNSIGNED_BYTE;
+	data->format = EPixelFormat::PixelFormat_RGB;
+	data->type = EPixelElementType::PixelType_UNSIGNED_BYTE;
 
 	data->PushUserdata(state);
 	return 1;
-- 
cgit v1.1-26-g67d0