|
Total |
Utf8-ucs2 |
Html_parse |
Layout |
Render_string |
Init_texture |
Ft_load_glyph |
原始 |
2293 |
1 |
26 |
708 |
1556 |
2 |
1403 |
|
|
|
|
|
|
|
|
上表用于记录优化各步骤的消耗时间。
生成的文本纹理,文本是加州宾馆的全歌词。
原始版本整个纹理的生成耗时2300毫秒左右,可以看到实际是慢得发指。
究其原因,是由于实现iron引擎的时候未进行任何性能方面的考虑。
上述时间表的构成:
total : 总消耗时间
utf8-ucs2: 将utf8字符串转换为ucs2的时间
html_parse : 引擎需要支持一定程度的富文本,所以需要支持简单的html解析.
render_string: 将字符串转换为纹理所消耗的总时间
Ft_load_glygh : 在整个过程中, 调用Ft_load_glygh 消耗的总时间。
由以上分析可知,最消耗时间的调用是Ft_load_glygh。
尚不知道为什么Ft_load_glygh消耗的时间这么大,原以为是因为每次Ft_load_glygh会到文件中去查询加载具体字符数据,而将程序改造成从内存加载字库数据,仍然耗时巨大。
如果freetype本身无法优化,那么就需要从其他方向来考虑这个问题。
首先重新阐述一下字体渲染的需求:
(1) 常规的字体属性需要支持,如font_size
(2) 能够为字体指定边框颜色,边框尺寸,填充颜色。
(3) 能够按单行,或者多行进行布局。
(4) 能够一定程度支持富文本, 例如为精灵设置text = <font style="color:#FF0000; ">某X</font>施展了<font style=" color:#FF0000;outline:1;outline_color:#00FFFF">愤怒一击</font>
(5) 性能不需要达到多高,但至少做到切换场景,不能因为字体纹理生成而产生明显卡顿(特别是有动态字体的时候,比如聊天).
综上所属,一次纹理生成的过程至少包含如下逻辑
--> 将utf8转换为ucs2
--> 解析富文本
--> 计算布局
--> 生成纹理
这里需要说明的是: 按上表所述, Layout 消耗掉708ms的原因是,Layout需要获取各字符的尺寸. 所以调用了FT_Load_Glyph, 该函数起码就占用了700ms。
之后在生成纹理过程中,对FT_Load_Glyph再次进行调用,所以不慢都不行。
问题大致清楚后,考虑解决方案.
目前初步考虑的优化方案是:避免每次生成字符纹理,都去调用Ft_load_glyph加载字模数据,改为采用缓存机制.仅在第一次加载字体时,才会调用Ft_load_glyph。之后的调用,会从缓存中读取。 至于是不是要对缓存设置阀值,控制内存增长,这里先暂时不考虑。
那么接下来就需要确定我到底应该缓存什么。
缓存什么呢,缓存什么呢。
先把参考用的freetype库,生成带边框字体的example代码贴上。
http://www.freetype.org/freetype2/docs/tutorial/example2.cpp
这个范例代码写得丑陋,但是逻辑还是很简单的。
大体上的过程实际就是加载字模后,
获取字模fill 部分的Span表,
获取字模outline 部分的Span表,
将两部分数据打到一个Bitmap中.
这个Span结构需要特别说明一下,很有意思。
struct Span { Span() { } Span(int _x, int _y, int _width, int _coverage) : x(_x), y(_y), width(_width), coverage(_coverage) { } int x, y, width, coverage; };
他实际描述的是一条横向扫描线,起点在(x, y), 宽度为with, converage 存储的是灰度数据(0-255)。你后面需要做的是拿到这个表以后,进行遍历,将Span数据外加外部输入的颜色值(边框颜色 和 填充颜色) 转换成最终的Bitmap。
由于我们的字体支持包边,所以我们可能会拿到两个Span表,一个是用于渲染outline的,姑且叫他outlineSpans, 另一个是用于渲染填充区的,姑且叫他fillSpans。
实际上,outlineSpan 和 fillSpan 所需要的Bitmap尺寸是不同的,通常是边框需要的Bitmap略大于填充区所需要的Bitmap。
Freetype的设计,由于是一次Ft_load_glyp获得outlineSpans 和 fillSpans, 所以可以猜想,他们的坐标系统是统一的,也就是说原点(0,0)点是重合的, 这也是为什么x, y 有时会出现负数的原因。
这个span啥的有个好处,实际上有了这个span, 基本上就可以脱离freetype的接口自己画文字了。当然他应该还有更raw的东西,目前没考虑要接触。
为了证实猜想,我首先做了一个测试。
打印出字符'g'的outlineSpans 和 fillSpans的数据.
其结果显示如下:
[2.24 19:55:11] [INFO] there are 94 span in fill rect. [2.24 19:55:11] [INFO] [0] x:2 y:-5 width:1 gray8:38 [2.24 19:55:11] [INFO] [1] x:3 y:-5 width:1 gray8:163 [2.24 19:55:11] [INFO] [2] x:4 y:-5 width:1 gray8:232 [2.24 19:55:11] [INFO] [3] x:5 y:-5 width:1 gray8:251 [2.24 19:55:11] [INFO] [4] x:6 y:-5 width:1 gray8:232 [2.24 19:55:11] [INFO] [5] x:7 y:-5 width:1 gray8:179 [2.24 19:55:11] [INFO] [6] x:8 y:-5 width:1 gray8:74 [2.24 19:55:11] [INFO] [7] x:2 y:-4 width:1 gray8:245 [2.24 19:55:11] [INFO] [8] x:3 y:-4 width:6 gray8:255 [2.24 19:55:11] [INFO] [9] x:9 y:-4 width:1 gray8:134 [2.24 19:55:11] [INFO] [10] x:2 y:-3 width:1 gray8:225 [2.24 19:55:11] [INFO] [11] x:3 y:-3 width:1 gray8:103 [2.24 19:55:11] [INFO] [12] x:4 y:-3 width:1 gray8:25 [2.24 19:55:11] [INFO] [13] x:5 y:-3 width:1 gray8:6 [2.24 19:55:11] [INFO] [14] x:6 y:-3 width:1 gray8:42 [2.24 19:55:11] [INFO] [15] x:7 y:-3 width:1 gray8:158 [2.24 19:55:11] [INFO] [16] x:8 y:-3 width:2 gray8:255 [2.24 19:55:11] [INFO] [17] x:10 y:-3 width:1 gray8:63 [2.24 19:55:11] [INFO] [18] x:2 y:-2 width:1 gray8:12 [2.24 19:55:11] [INFO] [19] x:8 y:-2 width:1 gray8:168 [2.24 19:55:11] [INFO] [20] x:9 y:-2 width:1 gray8:255 [2.24 19:55:11] [INFO] [21] x:10 y:-2 width:1 gray8:167 [2.24 19:55:11] [INFO] [22] x:8 y:-1 width:1 gray8:59 [2.24 19:55:11] [INFO] [23] x:9 y:-1 width:1 gray8:255 [2.24 19:55:11] [INFO] [24] x:10 y:-1 width:1 gray8:223 [2.24 19:55:11] [INFO] [25] x:2 y:0 width:1 gray8:16 [2.24 19:55:11] [INFO] [26] x:3 y:0 width:1 gray8:147 [2.24 19:55:11] [INFO] [27] x:4 y:0 width:1 gray8:230 [2.24 19:55:11] [INFO] [28] x:5 y:0 width:1 gray8:247 [2.24 19:55:11] [INFO] [29] x:6 y:0 width:1 gray8:206 [2.24 19:55:11] [INFO] [30] x:7 y:0 width:1 gray8:80 [2.24 19:55:11] [INFO] [31] x:8 y:0 width:1 gray8:13 [2.24 19:55:11] [INFO] [32] x:9 y:0 width:1 gray8:255 [2.24 19:55:11] [INFO] [33] x:10 y:0 width:1 gray8:247 [2.24 19:55:11] [INFO] [34] x:1 y:1 width:1 gray8:8 [2.24 19:55:11] [INFO] [35] x:2 y:1 width:1 gray8:207 [2.24 19:55:11] [INFO] [36] x:3 y:1 width:4 gray8:255 [2.24 19:55:11] [INFO] [37] x:7 y:1 width:1 gray8:254 [2.24 19:55:11] [INFO] [38] x:8 y:1 width:1 gray8:88 [2.24 19:55:11] [INFO] [39] x:9 y:1 width:2 gray8:255 [2.24 19:55:11] [INFO] [40] x:11 y:1 width:0 gray8:248 [2.24 19:55:11] [INFO] [41] x:1 y:2 width:1 gray8:119 [2.24 19:55:11] [INFO] [42] x:2 y:2 width:1 gray8:255 [2.24 19:55:11] [INFO] [43] x:3 y:2 width:1 gray8:247 [2.24 19:55:11] [INFO] [44] x:4 y:2 width:1 gray8:108 [2.24 19:55:11] [INFO] [45] x:5 y:2 width:1 gray8:21 [2.24 19:55:11] [INFO] [46] x:6 y:2 width:1 gray8:24 [2.24 19:55:11] [INFO] [47] x:7 y:2 width:1 gray8:113 [2.24 19:55:11] [INFO] [48] x:8 y:2 width:1 gray8:227 [2.24 19:55:11] [INFO] [49] x:9 y:2 width:2 gray8:255 [2.24 19:55:11] [INFO] [50] x:1 y:3 width:1 gray8:205 [2.24 19:55:11] [INFO] [51] x:2 y:3 width:1 gray8:255 [2.24 19:55:11] [INFO] [52] x:3 y:3 width:1 gray8:120 [2.24 19:55:11] [INFO] [53] x:8 y:3 width:1 gray8:114 [2.24 19:55:11] [INFO] [54] x:9 y:3 width:2 gray8:255 [2.24 19:55:11] [INFO] [55] x:1 y:4 width:1 gray8:244 [2.24 19:55:11] [INFO] [56] x:2 y:4 width:1 gray8:255 [2.24 19:55:11] [INFO] [57] x:3 y:4 width:1 gray8:31 [2.24 19:55:11] [INFO] [58] x:8 y:4 width:1 gray8:25 [2.24 19:55:11] [INFO] [59] x:9 y:4 width:2 gray8:255 [2.24 19:55:11] [INFO] [60] x:1 y:5 width:1 gray8:250 [2.24 19:55:11] [INFO] [61] x:2 y:5 width:1 gray8:255 [2.24 19:55:11] [INFO] [62] x:3 y:5 width:1 gray8:9 [2.24 19:55:11] [INFO] [63] x:9 y:5 width:2 gray8:255 [2.24 19:55:11] [INFO] [64] x:1 y:6 width:1 gray8:228 [2.24 19:55:11] [INFO] [65] x:2 y:6 width:1 gray8:255 [2.24 19:55:11] [INFO] [66] x:3 y:6 width:1 gray8:41 [2.24 19:55:11] [INFO] [67] x:8 y:6 width:1 gray8:10 [2.24 19:55:11] [INFO] [68] x:9 y:6 width:2 gray8:255 [2.24 19:55:11] [INFO] [69] x:1 y:7 width:1 gray8:172 [2.24 19:55:11] [INFO] [70] x:2 y:7 width:1 gray8:255 [2.24 19:55:11] [INFO] [71] x:3 y:7 width:1 gray8:141 [2.24 19:55:11] [INFO] [72] x:8 y:7 width:1 gray8:83 [2.24 19:55:11] [INFO] [73] x:9 y:7 width:2 gray8:255 [2.24 19:55:11] [INFO] [74] x:1 y:8 width:1 gray8:68 [2.24 19:55:11] [INFO] [75] x:2 y:8 width:1 gray8:255 [2.24 19:55:11] [INFO] [76] x:3 y:8 width:1 gray8:252 [2.24 19:55:11] [INFO] [77] x:4 y:8 width:1 gray8:128 [2.24 19:55:11] [INFO] [78] x:5 y:8 width:1 gray8:32 [2.24 19:55:11] [INFO] [79] x:6 y:8 width:1 gray8:16 [2.24 19:55:11] [INFO] [80] x:7 y:8 width:1 gray8:91 [2.24 19:55:11] [INFO] [81] x:8 y:8 width:1 gray8:235 [2.24 19:55:11] [INFO] [82] x:9 y:8 width:2 gray8:255 [2.24 19:55:11] [INFO] [83] x:2 y:9 width:1 gray8:147 [2.24 19:55:11] [INFO] [84] x:3 y:9 width:5 gray8:255 [2.24 19:55:11] [INFO] [85] x:8 y:9 width:1 gray8:142 [2.24 19:55:11] [INFO] [86] x:9 y:9 width:2 gray8:255 [2.24 19:55:11] [INFO] [87] x:3 y:10 width:1 gray8:100 [2.24 19:55:11] [INFO] [88] x:4 y:10 width:1 gray8:205 [2.24 19:55:11] [INFO] [89] x:5 y:10 width:1 gray8:246 [2.24 19:55:11] [INFO] [90] x:6 y:10 width:1 gray8:231 [2.24 19:55:11] [INFO] [91] x:7 y:10 width:1 gray8:132 [2.24 19:55:11] [INFO] [92] x:8 y:10 width:1 gray8:3 [2.24 19:55:11] [INFO] [93] x:9 y:10 width:2 gray8:255 [2.24 19:55:11] [INFO] fill rect :(0.000000,-5.000000) - (11.000000,10.000000), w:12.000000, h:16.000000 [2.24 19:55:11] [INFO] --------------------------------------------------- [2.24 19:55:11] [INFO] there are 91 span in outline rect. [2.24 19:55:11] [INFO] [0] x:2 y:-6 width:1 gray8:70 [2.24 19:55:11] [INFO] [1] x:3 y:-6 width:1 gray8:178 [2.24 19:55:11] [INFO] [2] x:4 y:-6 width:1 gray8:235 [2.24 19:55:11] [INFO] [3] x:5 y:-6 width:1 gray8:250 [2.24 19:55:11] [INFO] [4] x:6 y:-6 width:1 gray8:233 [2.24 19:55:11] [INFO] [5] x:7 y:-6 width:1 gray8:185 [2.24 19:55:11] [INFO] [6] x:8 y:-6 width:1 gray8:97 [2.24 19:55:11] [INFO] [7] x:9 y:-6 width:1 gray8:5 [2.24 19:55:11] [INFO] [8] x:1 y:-5 width:1 gray8:139 [2.24 19:55:11] [INFO] [9] x:2 y:-5 width:7 gray8:255 [2.24 19:55:11] [INFO] [10] x:9 y:-5 width:1 gray8:207 [2.24 19:55:11] [INFO] [11] x:10 y:-5 width:1 gray8:28 [2.24 19:55:11] [INFO] [12] x:1 y:-4 width:1 gray8:252 [2.24 19:55:11] [INFO] [13] x:2 y:-4 width:8 gray8:255 [2.24 19:55:11] [INFO] [14] x:10 y:-4 width:1 gray8:202 [2.24 19:55:11] [INFO] [15] x:11 y:-4 width:1 gray8:4 [2.24 19:55:11] [INFO] [16] x:1 y:-3 width:10 gray8:255 [2.24 19:55:11] [INFO] [17] x:11 y:-3 width:1 gray8:86 [2.24 19:55:11] [INFO] [18] x:1 y:-2 width:1 gray8:225 [2.24 19:55:11] [INFO] [19] x:2 y:-2 width:1 gray8:246 [2.24 19:55:11] [INFO] [20] x:3 y:-2 width:1 gray8:128 [2.24 19:55:11] [INFO] [21] x:4 y:-2 width:1 gray8:30 [2.24 19:55:11] [INFO] [22] x:5 y:-2 width:1 gray8:11 [2.24 19:55:11] [INFO] [23] x:6 y:-2 width:1 gray8:66 [2.24 19:55:11] [INFO] [24] x:7 y:-2 width:1 gray8:221 [2.24 19:55:11] [INFO] [25] x:8 y:-2 width:3 gray8:255 [2.24 19:55:11] [INFO] [26] x:11 y:-2 width:1 gray8:173 [2.24 19:55:11] [INFO] [27] x:1 y:-1 width:1 gray8:19 [2.24 19:55:11] [INFO] [28] x:2 y:-1 width:1 gray8:70 [2.24 19:55:11] [INFO] [29] x:3 y:-1 width:1 gray8:171 [2.24 19:55:11] [INFO] [30] x:4 y:-1 width:1 gray8:234 [2.24 19:55:11] [INFO] [31] x:5 y:-1 width:1 gray8:247 [2.24 19:55:11] [INFO] [32] x:6 y:-1 width:1 gray8:215 [2.24 19:55:11] [INFO] [33] x:7 y:-1 width:1 gray8:197 [2.24 19:55:11] [INFO] [34] x:8 y:-1 width:3 gray8:255 [2.24 19:55:11] [INFO] [35] x:11 y:-1 width:1 gray8:225 [2.24 19:55:11] [INFO] [36] x:1 y:0 width:1 gray8:81 [2.24 19:55:11] [INFO] [37] x:2 y:0 width:1 gray8:250 [2.24 19:55:11] [INFO] [38] x:3 y:0 width:8 gray8:255 [2.24 19:55:11] [INFO] [39] x:11 y:0 width:1 gray8:246 [2.24 19:55:11] [INFO] [40] x:0 y:1 width:1 gray8:29 [2.24 19:55:11] [INFO] [41] x:1 y:1 width:1 gray8:243 [2.24 19:55:11] [INFO] [42] x:2 y:1 width:10 gray8:255 [2.24 19:55:11] [INFO] [43] x:12 y:1 width:0 gray8:248 [2.24 19:55:11] [INFO] [44] x:0 y:2 width:1 gray8:139 [2.24 19:55:11] [INFO] [45] x:1 y:2 width:11 gray8:255 [2.24 19:55:11] [INFO] [46] x:0 y:3 width:1 gray8:211 [2.24 19:55:11] [INFO] [47] x:1 y:3 width:3 gray8:255 [2.24 19:55:11] [INFO] [48] x:4 y:3 width:1 gray8:177 [2.24 19:55:11] [INFO] [49] x:5 y:3 width:1 gray8:22 [2.24 19:55:11] [INFO] [50] x:6 y:3 width:1 gray8:25 [2.24 19:55:11] [INFO] [51] x:7 y:3 width:1 gray8:175 [2.24 19:55:11] [INFO] [52] x:8 y:3 width:4 gray8:255 [2.24 19:55:11] [INFO] [53] x:0 y:4 width:1 gray8:245 [2.24 19:55:11] [INFO] [54] x:1 y:4 width:3 gray8:255 [2.24 19:55:11] [INFO] [55] x:4 y:4 width:1 gray8:34 [2.24 19:55:11] [INFO] [56] x:7 y:4 width:1 gray8:29 [2.24 19:55:11] [INFO] [57] x:8 y:4 width:4 gray8:255 [2.24 19:55:11] [INFO] [58] x:0 y:5 width:1 gray8:250 [2.24 19:55:11] [INFO] [59] x:1 y:5 width:3 gray8:255 [2.24 19:55:11] [INFO] [60] x:4 y:5 width:1 gray8:9 [2.24 19:55:11] [INFO] [61] x:8 y:5 width:4 gray8:255 [2.24 19:55:11] [INFO] [62] x:0 y:6 width:1 gray8:230 [2.24 19:55:11] [INFO] [63] x:1 y:6 width:3 gray8:255 [2.24 19:55:11] [INFO] [64] x:4 y:6 width:1 gray8:48 [2.24 19:55:11] [INFO] [65] x:7 y:6 width:1 gray8:9 [2.24 19:55:11] [INFO] [66] x:8 y:6 width:4 gray8:255 [2.24 19:55:11] [INFO] [67] x:0 y:7 width:1 gray8:181 [2.24 19:55:11] [INFO] [68] x:1 y:7 width:3 gray8:255 [2.24 19:55:11] [INFO] [69] x:4 y:7 width:1 gray8:191 [2.24 19:55:11] [INFO] [70] x:5 y:7 width:1 gray8:34 [2.24 19:55:11] [INFO] [71] x:6 y:7 width:1 gray8:17 [2.24 19:55:11] [INFO] [72] x:7 y:7 width:1 gray8:149 [2.24 19:55:11] [INFO] [73] x:8 y:7 width:4 gray8:255 [2.24 19:55:11] [INFO] [74] x:0 y:8 width:1 gray8:93 [2.24 19:55:11] [INFO] [75] x:1 y:8 width:11 gray8:255 [2.24 19:55:11] [INFO] [76] x:0 y:9 width:1 gray8:5 [2.24 19:55:11] [INFO] [77] x:1 y:9 width:1 gray8:207 [2.24 19:55:11] [INFO] [78] x:2 y:9 width:10 gray8:255 [2.24 19:55:11] [INFO] [79] x:1 y:10 width:1 gray8:32 [2.24 19:55:11] [INFO] [80] x:2 y:10 width:1 gray8:222 [2.24 19:55:11] [INFO] [81] x:3 y:10 width:9 gray8:255 [2.24 19:55:11] [INFO] [82] x:2 y:11 width:1 gray8:13 [2.24 19:55:11] [INFO] [83] x:3 y:11 width:1 gray8:126 [2.24 19:55:11] [INFO] [84] x:4 y:11 width:1 gray8:212 [2.24 19:55:11] [INFO] [85] x:5 y:11 width:1 gray8:246 [2.24 19:55:11] [INFO] [86] x:6 y:11 width:1 gray8:230 [2.24 19:55:11] [INFO] [87] x:7 y:11 width:1 gray8:159 [2.24 19:55:11] [INFO] [88] x:8 y:11 width:1 gray8:212 [2.24 19:55:11] [INFO] [89] x:9 y:11 width:2 gray8:255 [2.24 19:55:11] [INFO] [90] x:11 y:11 width:1 gray8:180 [2.24 19:55:11] [INFO] outline rect :(0.000000,-6.000000) - (12.000000,11.000000), w:13.000000, h:18.000000 [2.24 19:55:11] [INFO] overlapped rect :(0.000000,-6.000000) - (12.000000,11.000000), w:13.000000, h:18.000000由此可以得到:
填充区一共有94个span, 分布在坐标左上(0,-5) 右下(11,10) , 其矩形区域尺寸为(12,16)
沟边区一共有91个span, 分别在(0, -6) (12,11) 其矩形区域尺寸为(13,18)
填充与沟边的合成位图最终需要尺寸(13, 18)
妈呀,一个g 有94 + 91 = 185个span 只是一个g.
但是鉴于计算机处理的速度比我快,所以先忽略继续往下走起。
范例中,设置颜色到bitmap的代码是:
charBitmap[(int)((imgHeight - 1 - (s->y - rect.ymin)) * imgWidth + s->x - rect.xmin + w)] = outLineColor;
所以Bitmap 与 fillRect的坐标映射关系是:
y = (imgHeight - 1 - (s->y - rect.ymin)) * imgWidth
x = s->x - rect.xmin
实际上是完成形如下图的坐标变换:
那么实际上,可以较为轻松的分别保存outlineBitmap 和 fillBitmap , 用于存储灰度.并记录offsetX, offsetY 作为坐标参考系对齐的依据。
但是,后来回过头来考虑这个问题,我干嘛要分别存储2个bitmap, 难道是像复用fillBitmap么? 没有啊,所以我不用分别存储outlineBitmap和fillBitmap,仅需要存储一个总的bitmap, 其大小是outline rect 和 fill rect 的bound rect.然后将两个灰度存入就行了。实际上,由于很多设备不支持2通道纹理,这里我选择采用RGBA8888的格式存储, R通道存储填充灰度, G通道存储边框灰度。浪费了2个通道实在属于无奈之举,但shader可以直接拿到这个texture做渲染,也是件好事。
除了bitmap需要关注,还需要取得相关的char metrics 并缓存下来, 因为Layout逻辑需要用到这些位置相关的数据。具体需要的值参考下图:
另需要注意的是,由于对边框的支持, 所以可能会对一些位置数据进行修正。
需要修正的数据包括:
bearingX, bearingY, width, height, advance.
如果不调整会这样?那么在字符有边框的时候,后面的字符很可能把前面的盖住。
怎么调整呢,嗯,嗯。直接写代码调整,对。
所以整理下载,缓存的结构体大概是这样的:
CharChache
bitmap : 纹理位图(r,g有用处, b,a 没用, 也许将来可以写点啥在里面)
charMetrics
-bearingX
-bearingY
-advance
-width
-height
那么缓存的Key怎么考虑呢
Key包含一下部分:
char (uint16) 字符的unicode
font_size(uint8)
outline_size(unit8)
font_size 和 outline_size 采用uint8的原因是, 这样可以用一个32位整形数来作为缓存对象的键值,使用超过一个字节的情况存储font_size 和 outline_size 不做考虑,因为那种情况太极端了。
剩下的工作就相当的轻松了.我可以把大致需要的接口做个列表:
void renderString(string _str, TextStyle _defaultStyle, Texture2D _outTexture)
这个是整个文字渲染的进入点接口, 可以按Factory模式处理,目前实现FreeTypeWithBitmapCache 实现, 将来还可以搞个Device 实现,直接向操作系统要纹理,比如ios本身似乎是支持包边字体纹理生成的。
_defaultStyle 参数是文本的样式参数,包含行间距,字符间距,是否换行,换行宽度,首行indent,字体颜色, 边框颜色等信息.
总之,这个接口就是我把字符串给你,你按我要的效果给生成纹理。
void htmlParse(string _str, HtmlTagList _outHtmlTagList, string _outPureString)
该方法是解析富文本字符串(其实不是html,算是一种私有协议)。
输出的HtmlTagList 是解析的结果,他不是一颗树,实际只是一个链表而已(不想做那么复杂, 因为我压根就没打算支持标签的嵌套,简单实现即可,不必搞成浏览器,如果策划问为啥不支持嵌套表格,文本输入框, 嵌图片,为啥没有播放音频功能,直接耳屎扇飞)。
_outPureString 是纯文本的内容,实际也可以通过_outHtmlList 分析得到,但是这个方法输出来,作为顺便完成的工作.
ChatCacheEntry* queryCharCache(wchar _ch, uint8 _fontSize, _unit8 _outlineSize)
查询缓存, 如果缓存中不存在, 则按之前分析的逻辑生成ChatCacheEntry。
这里还有一个可优化的地方.就是可以在ChatCacheEntry中存放一个命中次数,内部按该次数对ChatChacheEntry进行排序,在适当的时候删除掉低命中次数的缓存条目,这样可以避免文字缓存把内存搞爆的情况。
void layout(string _str, TextStyle _style, vector<CharMetrics> _metrics, vector<Point> _outPos)
该方法接受字符串,样式,以及与字符串对应的每个字符的metrcis信息,该方法对整个字符串进行布局,并将位置输出到_outPos中。
始终 _str.length = _metrics.size = _outPos.size
所以最核心的方法就是上述这些。
其中客户端真正调用的就是 renderString, 其他接口都是为renderString服务,在renderString内部被调用的。
最后就是shader
shader很简单,
传入 fillColor, outlineColor
传入 纹理 texture
那么pixel颜色为
outlineColor.rgb = outlineColor.rgb
outlineColor.a = texture.r
outColor.rgb = outlineColor.rgb + (fillColor.rgb - outlineColor.rgb) * texture.g
outColor.a = outlineColor.a + texture.g
然后,就基本上没有然后了。
云风有篇博文提到了一种方案,提出直接用一张大texture 作为文字的缓存。有兴趣可以去看下,不过我基于以下原因暂时不打算采用。
其一:这一版本我的目标仅是性能足够而非性能最优。
其二:大纹理并且随着新字符的生成和老字符的移除,同样会涉及主存和显存的换入换出,如果更新频繁,该方案是否总体上有益不能确定。
其三:我们的系统font_size 的尺寸不好估量12pt 和 24pt有可能都有,涉及到装箱算法,如果单页满了,还可能会做multi paging , 总的来说可能会增加大量复杂度。
东西一复杂了我就拉不出屎了。先看看吧,先看看。
所以目前还是先简单实现一版,看看性能如何再说。
该文档。。那啥,主要是整理自己的思路写下的日志和开发参考,大量细节都省略。所以估计很难阅读。也可能有超多的错漏。
嗯,嗯,明天开始编码。
现在先去看行尸走肉