zoukankan      html  css  js  c++  java
  • LOG.ZS.0001.基于Freetype的游戏字体渲染优化思路

     

    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 1 gray8:38
    
    [2.24 19:55:11]      [INFO]   [1] x:3 y:-5 1 gray8:163
    
    [2.24 19:55:11]      [INFO]   [2] x:4 y:-5 1 gray8:232
    
    [2.24 19:55:11]      [INFO]   [3] x:5 y:-5 1 gray8:251
    
    [2.24 19:55:11]      [INFO]   [4] x:6 y:-5 1 gray8:232
    
    [2.24 19:55:11]      [INFO]   [5] x:7 y:-5 1 gray8:179
    
    [2.24 19:55:11]      [INFO]   [6] x:8 y:-5 1 gray8:74
    
    [2.24 19:55:11]      [INFO]   [7] x:2 y:-4 1 gray8:245
    
    [2.24 19:55:11]      [INFO]   [8] x:3 y:-4 6 gray8:255
    
    [2.24 19:55:11]      [INFO]   [9] x:9 y:-4 1 gray8:134
    
    [2.24 19:55:11]      [INFO]   [10] x:2 y:-3 1 gray8:225
    
    [2.24 19:55:11]      [INFO]   [11] x:3 y:-3 1 gray8:103
    
    [2.24 19:55:11]      [INFO]   [12] x:4 y:-3 1 gray8:25
    
    [2.24 19:55:11]      [INFO]   [13] x:5 y:-3 1 gray8:6
    
    [2.24 19:55:11]      [INFO]   [14] x:6 y:-3 1 gray8:42
    
    [2.24 19:55:11]      [INFO]   [15] x:7 y:-3 1 gray8:158
    
    [2.24 19:55:11]      [INFO]   [16] x:8 y:-3 2 gray8:255
    
    [2.24 19:55:11]      [INFO]   [17] x:10 y:-3 1 gray8:63
    
    [2.24 19:55:11]      [INFO]   [18] x:2 y:-2 1 gray8:12
    
    [2.24 19:55:11]      [INFO]   [19] x:8 y:-2 1 gray8:168
    
    [2.24 19:55:11]      [INFO]   [20] x:9 y:-2 1 gray8:255
    
    [2.24 19:55:11]      [INFO]   [21] x:10 y:-2 1 gray8:167
    
    [2.24 19:55:11]      [INFO]   [22] x:8 y:-1 1 gray8:59
    
    [2.24 19:55:11]      [INFO]   [23] x:9 y:-1 1 gray8:255
    
    [2.24 19:55:11]      [INFO]   [24] x:10 y:-1 1 gray8:223
    
    [2.24 19:55:11]      [INFO]   [25] x:2 y:0 1 gray8:16
    
    [2.24 19:55:11]      [INFO]   [26] x:3 y:0 1 gray8:147
    
    [2.24 19:55:11]      [INFO]   [27] x:4 y:0 1 gray8:230
    
    [2.24 19:55:11]      [INFO]   [28] x:5 y:0 1 gray8:247
    
    [2.24 19:55:11]      [INFO]   [29] x:6 y:0 1 gray8:206
    
    [2.24 19:55:11]      [INFO]   [30] x:7 y:0 1 gray8:80
    
    [2.24 19:55:11]      [INFO]   [31] x:8 y:0 1 gray8:13
    
    [2.24 19:55:11]      [INFO]   [32] x:9 y:0 1 gray8:255
    
    [2.24 19:55:11]      [INFO]   [33] x:10 y:0 1 gray8:247
    
    [2.24 19:55:11]      [INFO]   [34] x:1 y:1 1 gray8:8
    
    [2.24 19:55:11]      [INFO]   [35] x:2 y:1 1 gray8:207
    
    [2.24 19:55:11]      [INFO]   [36] x:3 y:1 4 gray8:255
    
    [2.24 19:55:11]      [INFO]   [37] x:7 y:1 1 gray8:254
    
    [2.24 19:55:11]      [INFO]   [38] x:8 y:1 1 gray8:88
    
    [2.24 19:55:11]      [INFO]   [39] x:9 y:1 2 gray8:255
    
    [2.24 19:55:11]      [INFO]   [40] x:11 y:1 0 gray8:248
    
    [2.24 19:55:11]      [INFO]   [41] x:1 y:2 1 gray8:119
    
    [2.24 19:55:11]      [INFO]   [42] x:2 y:2 1 gray8:255
    
    [2.24 19:55:11]      [INFO]   [43] x:3 y:2 1 gray8:247
    
    [2.24 19:55:11]      [INFO]   [44] x:4 y:2 1 gray8:108
    
    [2.24 19:55:11]      [INFO]   [45] x:5 y:2 1 gray8:21
    
    [2.24 19:55:11]      [INFO]   [46] x:6 y:2 1 gray8:24
    
    [2.24 19:55:11]      [INFO]   [47] x:7 y:2 1 gray8:113
    
    [2.24 19:55:11]      [INFO]   [48] x:8 y:2 1 gray8:227
    
    [2.24 19:55:11]      [INFO]   [49] x:9 y:2 2 gray8:255
    
    [2.24 19:55:11]      [INFO]   [50] x:1 y:3 1 gray8:205
    
    [2.24 19:55:11]      [INFO]   [51] x:2 y:3 1 gray8:255
    
    [2.24 19:55:11]      [INFO]   [52] x:3 y:3 1 gray8:120
    
    [2.24 19:55:11]      [INFO]   [53] x:8 y:3 1 gray8:114
    
    [2.24 19:55:11]      [INFO]   [54] x:9 y:3 2 gray8:255
    
    [2.24 19:55:11]      [INFO]   [55] x:1 y:4 1 gray8:244
    
    [2.24 19:55:11]      [INFO]   [56] x:2 y:4 1 gray8:255
    
    [2.24 19:55:11]      [INFO]   [57] x:3 y:4 1 gray8:31
    
    [2.24 19:55:11]      [INFO]   [58] x:8 y:4 1 gray8:25
    
    [2.24 19:55:11]      [INFO]   [59] x:9 y:4 2 gray8:255
    
    [2.24 19:55:11]      [INFO]   [60] x:1 y:5 1 gray8:250
    
    [2.24 19:55:11]      [INFO]   [61] x:2 y:5 1 gray8:255
    
    [2.24 19:55:11]      [INFO]   [62] x:3 y:5 1 gray8:9
    
    [2.24 19:55:11]      [INFO]   [63] x:9 y:5 2 gray8:255
    
    [2.24 19:55:11]      [INFO]   [64] x:1 y:6 1 gray8:228
    
    [2.24 19:55:11]      [INFO]   [65] x:2 y:6 1 gray8:255
    
    [2.24 19:55:11]      [INFO]   [66] x:3 y:6 1 gray8:41
    
    [2.24 19:55:11]      [INFO]   [67] x:8 y:6 1 gray8:10
    
    [2.24 19:55:11]      [INFO]   [68] x:9 y:6 2 gray8:255
    
    [2.24 19:55:11]      [INFO]   [69] x:1 y:7 1 gray8:172
    
    [2.24 19:55:11]      [INFO]   [70] x:2 y:7 1 gray8:255
    
    [2.24 19:55:11]      [INFO]   [71] x:3 y:7 1 gray8:141
    
    [2.24 19:55:11]      [INFO]   [72] x:8 y:7 1 gray8:83
    
    [2.24 19:55:11]      [INFO]   [73] x:9 y:7 2 gray8:255
    
    [2.24 19:55:11]      [INFO]   [74] x:1 y:8 1 gray8:68
    
    [2.24 19:55:11]      [INFO]   [75] x:2 y:8 1 gray8:255
    
    [2.24 19:55:11]      [INFO]   [76] x:3 y:8 1 gray8:252
    
    [2.24 19:55:11]      [INFO]   [77] x:4 y:8 1 gray8:128
    
    [2.24 19:55:11]      [INFO]   [78] x:5 y:8 1 gray8:32
    
    [2.24 19:55:11]      [INFO]   [79] x:6 y:8 1 gray8:16
    
    [2.24 19:55:11]      [INFO]   [80] x:7 y:8 1 gray8:91
    
    [2.24 19:55:11]      [INFO]   [81] x:8 y:8 1 gray8:235
    
    [2.24 19:55:11]      [INFO]   [82] x:9 y:8 2 gray8:255
    
    [2.24 19:55:11]      [INFO]   [83] x:2 y:9 1 gray8:147
    
    [2.24 19:55:11]      [INFO]   [84] x:3 y:9 5 gray8:255
    
    [2.24 19:55:11]      [INFO]   [85] x:8 y:9 1 gray8:142
    
    [2.24 19:55:11]      [INFO]   [86] x:9 y:9 2 gray8:255
    
    [2.24 19:55:11]      [INFO]   [87] x:3 y:10 1 gray8:100
    
    [2.24 19:55:11]      [INFO]   [88] x:4 y:10 1 gray8:205
    
    [2.24 19:55:11]      [INFO]   [89] x:5 y:10 1 gray8:246
    
    [2.24 19:55:11]      [INFO]   [90] x:6 y:10 1 gray8:231
    
    [2.24 19:55:11]      [INFO]   [91] x:7 y:10 1 gray8:132
    
    [2.24 19:55:11]      [INFO]   [92] x:8 y:10 1 gray8:3
    
    [2.24 19:55:11]      [INFO]   [93] x:9 y:10 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 1 gray8:70
    
    [2.24 19:55:11]      [INFO]   [1] x:3 y:-6 1 gray8:178
    
    [2.24 19:55:11]      [INFO]   [2] x:4 y:-6 1 gray8:235
    
    [2.24 19:55:11]      [INFO]   [3] x:5 y:-6 1 gray8:250
    
    [2.24 19:55:11]      [INFO]   [4] x:6 y:-6 1 gray8:233
    
    [2.24 19:55:11]      [INFO]   [5] x:7 y:-6 1 gray8:185
    
    [2.24 19:55:11]      [INFO]   [6] x:8 y:-6 1 gray8:97
    
    [2.24 19:55:11]      [INFO]   [7] x:9 y:-6 1 gray8:5
    
    [2.24 19:55:11]      [INFO]   [8] x:1 y:-5 1 gray8:139
    
    [2.24 19:55:11]      [INFO]   [9] x:2 y:-5 7 gray8:255
    
    [2.24 19:55:11]      [INFO]   [10] x:9 y:-5 1 gray8:207
    
    [2.24 19:55:11]      [INFO]   [11] x:10 y:-5 1 gray8:28
    
    [2.24 19:55:11]      [INFO]   [12] x:1 y:-4 1 gray8:252
    
    [2.24 19:55:11]      [INFO]   [13] x:2 y:-4 8 gray8:255
    
    [2.24 19:55:11]      [INFO]   [14] x:10 y:-4 1 gray8:202
    
    [2.24 19:55:11]      [INFO]   [15] x:11 y:-4 1 gray8:4
    
    [2.24 19:55:11]      [INFO]   [16] x:1 y:-3 10 gray8:255
    
    [2.24 19:55:11]      [INFO]   [17] x:11 y:-3 1 gray8:86
    
    [2.24 19:55:11]      [INFO]   [18] x:1 y:-2 1 gray8:225
    
    [2.24 19:55:11]      [INFO]   [19] x:2 y:-2 1 gray8:246
    
    [2.24 19:55:11]      [INFO]   [20] x:3 y:-2 1 gray8:128
    
    [2.24 19:55:11]      [INFO]   [21] x:4 y:-2 1 gray8:30
    
    [2.24 19:55:11]      [INFO]   [22] x:5 y:-2 1 gray8:11
    
    [2.24 19:55:11]      [INFO]   [23] x:6 y:-2 1 gray8:66
    
    [2.24 19:55:11]      [INFO]   [24] x:7 y:-2 1 gray8:221
    
    [2.24 19:55:11]      [INFO]   [25] x:8 y:-2 3 gray8:255
    
    [2.24 19:55:11]      [INFO]   [26] x:11 y:-2 1 gray8:173
    
    [2.24 19:55:11]      [INFO]   [27] x:1 y:-1 1 gray8:19
    
    [2.24 19:55:11]      [INFO]   [28] x:2 y:-1 1 gray8:70
    
    [2.24 19:55:11]      [INFO]   [29] x:3 y:-1 1 gray8:171
    
    [2.24 19:55:11]      [INFO]   [30] x:4 y:-1 1 gray8:234
    
    [2.24 19:55:11]      [INFO]   [31] x:5 y:-1 1 gray8:247
    
    [2.24 19:55:11]      [INFO]   [32] x:6 y:-1 1 gray8:215
    
    [2.24 19:55:11]      [INFO]   [33] x:7 y:-1 1 gray8:197
    
    [2.24 19:55:11]      [INFO]   [34] x:8 y:-1 3 gray8:255
    
    [2.24 19:55:11]      [INFO]   [35] x:11 y:-1 1 gray8:225
    
    [2.24 19:55:11]      [INFO]   [36] x:1 y:0 1 gray8:81
    
    [2.24 19:55:11]      [INFO]   [37] x:2 y:0 1 gray8:250
    
    [2.24 19:55:11]      [INFO]   [38] x:3 y:0 8 gray8:255
    
    [2.24 19:55:11]      [INFO]   [39] x:11 y:0 1 gray8:246
    
    [2.24 19:55:11]      [INFO]   [40] x:0 y:1 1 gray8:29
    
    [2.24 19:55:11]      [INFO]   [41] x:1 y:1 1 gray8:243
    
    [2.24 19:55:11]      [INFO]   [42] x:2 y:1 10 gray8:255
    
    [2.24 19:55:11]      [INFO]   [43] x:12 y:1 0 gray8:248
    
    [2.24 19:55:11]      [INFO]   [44] x:0 y:2 1 gray8:139
    
    [2.24 19:55:11]      [INFO]   [45] x:1 y:2 11 gray8:255
    
    [2.24 19:55:11]      [INFO]   [46] x:0 y:3 1 gray8:211
    
    [2.24 19:55:11]      [INFO]   [47] x:1 y:3 3 gray8:255
    
    [2.24 19:55:11]      [INFO]   [48] x:4 y:3 1 gray8:177
    
    [2.24 19:55:11]      [INFO]   [49] x:5 y:3 1 gray8:22
    
    [2.24 19:55:11]      [INFO]   [50] x:6 y:3 1 gray8:25
    
    [2.24 19:55:11]      [INFO]   [51] x:7 y:3 1 gray8:175
    
    [2.24 19:55:11]      [INFO]   [52] x:8 y:3 4 gray8:255
    
    [2.24 19:55:11]      [INFO]   [53] x:0 y:4 1 gray8:245
    
    [2.24 19:55:11]      [INFO]   [54] x:1 y:4 3 gray8:255
    
    [2.24 19:55:11]      [INFO]   [55] x:4 y:4 1 gray8:34
    
    [2.24 19:55:11]      [INFO]   [56] x:7 y:4 1 gray8:29
    
    [2.24 19:55:11]      [INFO]   [57] x:8 y:4 4 gray8:255
    
    [2.24 19:55:11]      [INFO]   [58] x:0 y:5 1 gray8:250
    
    [2.24 19:55:11]      [INFO]   [59] x:1 y:5 3 gray8:255
    
    [2.24 19:55:11]      [INFO]   [60] x:4 y:5 1 gray8:9
    
    [2.24 19:55:11]      [INFO]   [61] x:8 y:5 4 gray8:255
    
    [2.24 19:55:11]      [INFO]   [62] x:0 y:6 1 gray8:230
    
    [2.24 19:55:11]      [INFO]   [63] x:1 y:6 3 gray8:255
    
    [2.24 19:55:11]      [INFO]   [64] x:4 y:6 1 gray8:48
    
    [2.24 19:55:11]      [INFO]   [65] x:7 y:6 1 gray8:9
    
    [2.24 19:55:11]      [INFO]   [66] x:8 y:6 4 gray8:255
    
    [2.24 19:55:11]      [INFO]   [67] x:0 y:7 1 gray8:181
    
    [2.24 19:55:11]      [INFO]   [68] x:1 y:7 3 gray8:255
    
    [2.24 19:55:11]      [INFO]   [69] x:4 y:7 1 gray8:191
    
    [2.24 19:55:11]      [INFO]   [70] x:5 y:7 1 gray8:34
    
    [2.24 19:55:11]      [INFO]   [71] x:6 y:7 1 gray8:17
    
    [2.24 19:55:11]      [INFO]   [72] x:7 y:7 1 gray8:149
    
    [2.24 19:55:11]      [INFO]   [73] x:8 y:7 4 gray8:255
    
    [2.24 19:55:11]      [INFO]   [74] x:0 y:8 1 gray8:93
    
    [2.24 19:55:11]      [INFO]   [75] x:1 y:8 11 gray8:255
    
    [2.24 19:55:11]      [INFO]   [76] x:0 y:9 1 gray8:5
    
    [2.24 19:55:11]      [INFO]   [77] x:1 y:9 1 gray8:207
    
    [2.24 19:55:11]      [INFO]   [78] x:2 y:9 10 gray8:255
    
    [2.24 19:55:11]      [INFO]   [79] x:1 y:10 1 gray8:32
    
    [2.24 19:55:11]      [INFO]   [80] x:2 y:10 1 gray8:222
    
    [2.24 19:55:11]      [INFO]   [81] x:3 y:10 9 gray8:255
    
    [2.24 19:55:11]      [INFO]   [82] x:2 y:11 1 gray8:13
    
    [2.24 19:55:11]      [INFO]   [83] x:3 y:11 1 gray8:126
    
    [2.24 19:55:11]      [INFO]   [84] x:4 y:11 1 gray8:212
    
    [2.24 19:55:11]      [INFO]   [85] x:5 y:11 1 gray8:246
    
    [2.24 19:55:11]      [INFO]   [86] x:6 y:11 1 gray8:230
    
    [2.24 19:55:11]      [INFO]   [87] x:7 y:11 1 gray8:159
    
    [2.24 19:55:11]      [INFO]   [88] x:8 y:11 1 gray8:212
    
    [2.24 19:55:11]      [INFO]   [89] x:9 y:11 2 gray8:255
    
    [2.24 19:55:11]      [INFO]   [90] x:11 y:11 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 , 总的来说可能会增加大量复杂度。

    东西一复杂了我就拉不出屎了。先看看吧,先看看。

    所以目前还是先简单实现一版,看看性能如何再说。

    该文档。。那啥,主要是整理自己的思路写下的日志和开发参考,大量细节都省略。所以估计很难阅读。也可能有超多的错漏。

    嗯,嗯,明天开始编码。

    现在先去看行尸走肉

  • 相关阅读:
    【转】ORACLE日期时间 等函数大全
    list_car()函数小记
    git代码提交流程
    windows连接ubuntu服务器方式
    win10专业版安装docker实战
    selenium来识别数字验证码
    web服务器、WSGI跟Flask(等框架)之间的关系
    pymysql的使用
    sql常用 语句总结
    sql语句insert into where 错误解析
  • 原文地址:https://www.cnblogs.com/BearOcean/p/4298991.html
Copyright © 2011-2022 走看看