summaryrefslogtreecommitdiff
path: root/Runtime/GUI/Font.h
blob: df0bc7b09983f8fd9f7a464d98912fe3575cf874 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
#pragma once 

#include "Runtime/Utilities/Singleton.h"
#include "Runtime/Graphics/Texture.h"
#include "freetype.h"
#include "Runtime/Lua/LuaHelper.h"
#include "Runtime/Common/DataBuffer.h"
#include "Runtime/Math/Math.h"

#include <string>
#include <unordered_map>
#include <exception>
#include <vector>

//https://github.com/kaienfr/Font

struct Character {
	unsigned int atlas;    // atlas索引
	Rect position; // 在altas里的位置,以左上角为原点的,和GL的Y镜像
	Vector2 bearing;  // 左上角相对于原点的偏移
	unsigned int advance;  // 总宽,算上了间隔
};

namespace character
{
#if GAMELAB_WIN
	typedef unsigned short Unicode; // unicode codepoint(BMP,U+0000至U+FFFF)
#else 
    typedef unsigned int Unicode; // unicode codepoint(BMP,U+0000至U+FFFF)
#endif

	union Hash {
		unsigned int hashCode;
#pragma pack(1)
		struct {
			Unicode codepoint;
			unsigned short size;//字体大小
		};
#pragma pack(pop)

		bool operator==(const Hash &other) const
		{
			return codepoint == other.codepoint && size == other.size;
		}
	};
}

struct UnicodeString
{
	character::Unicode* str;
	int length;
};

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;        // 尺寸

	Vector2 cursor; // 游标,从左上角(0,0)开始
	int rowHeight;            // 当前行的高度
};

struct TextGeneratingSettings
{
	Vector2 atlasSize; // atlas的尺寸
	int margin;  // atlas的边界
	int padding; // glyph相互之间的间距,防止采样的时候越界
};

class FontException : public std::exception 
{
public:
    FontException(const char* what)
        : std::exception(what)
    {
    }
};

enum EEncoding
{
    Encoding_ASCII,
    Encoding_UTF8,
    Encoding_UTF16,
};

// 没有字形,但是有advance的文字,比如space和tab
#define FONT_NOT_IN_ATLAS_PLACEHOLDER (INT_MAX)

// 单个字体
class Font : public LuaBind::NativeClass<Font>
{
public:
    Font(std::string path, TextGeneratingSettings setting)/*throw FontException*/;
    Font(LuaBind::VM* vm, std::string path, TextGeneratingSettings setting)/*throw FontException*/;
    Font(DataBuffer* db, TextGeneratingSettings setting)/*throw FontException*/;
    Font(LuaBind::VM* vm, DataBuffer* db, TextGeneratingSettings setting)/*throw FontException*/;

	const Character* GetCharacter(character::Unicode codepoint, int pixelSize);
	const GlyphAtals* GetGlyphAtlas(int index);

	// pre-bake
	bool RenderCharacter(character::Unicode codepoint, int pixelSize);
    void RenderCharacters(character::Unicode* codepoint, int n, int pixelSize);
    void RenderCharacters(std::vector<character::Unicode>& codepoint, int pixelSize);

    GET(Vector2, AtlasSize, m_AtlasSize);

private:
	Texture* CreateAtlas();
	GlyphAtals* RequestAtlas(int pixelSize, Vector2 preferSize);
	Rect GetRenderChartAndMove(GlyphAtals* atlas, Vector2 preferSize);
	bool HasEnoughSpace(GlyphAtals* atlas, Vector2 preferSize);
	character::Hash GetHash(character::Unicode Unicode, int pixelSize);

    //-------------------------------------------------------------------------

	std::unordered_map<character::Hash, Character> m_Characters; // 渲染完的文字

	std::vector<GlyphAtals> m_Atlases; // 当前所有的atlas,由font完全拥有所有权,所以是lightuserdata
	std::unordered_map<int/*pixelSize*/, GlyphAtals*> m_AtlasCache;  // 快速找到可用的atlas

    bool m_IsEnabled;

	Vector2 m_AtlasSize;
    int     m_AtlasMargin;
    int     m_GlyphPadding;

	FT_Library m_FTLibrary;
	FT_Face    m_FTFace;

    //-------------------------------------------------------------------------

    LUA_BIND_DECL_CLASS(Font);

    LUA_BIND_DECL_METHOD(_New);
    LUA_BIND_DECL_METHOD(_GetCharacter);
    LUA_BIND_DECL_METHOD(_GetCharacters);
    LUA_BIND_DECL_METHOD(_GetGlyphAtlas);

};

namespace TextHelper
{

	void print_glyph(unsigned char* glyph, int width, int height);

}