惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

H
Help Net Security
F
Fortinet All Blogs
Engineering at Meta
Engineering at Meta
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
T
The Exploit Database - CXSecurity.com
H
Hackread – Cybersecurity News, Data Breaches, AI and More
I
Intezer
P
Privacy & Cybersecurity Law Blog
M
MIT News - Artificial intelligence
MyScale Blog
MyScale Blog
P
Privacy International News Feed
MongoDB | Blog
MongoDB | Blog
Project Zero
Project Zero
C
Cyber Attacks, Cyber Crime and Cyber Security
T
Tenable Blog
Security Latest
Security Latest
Stack Overflow Blog
Stack Overflow Blog
L
Lohrmann on Cybersecurity
V
Vulnerabilities – Threatpost
Microsoft Azure Blog
Microsoft Azure Blog
NISL@THU
NISL@THU
T
Threat Research - Cisco Blogs
L
LangChain Blog
Simon Willison's Weblog
Simon Willison's Weblog
WordPress大学
WordPress大学
SecWiki News
SecWiki News
博客园 - 三生石上(FineUI控件)
Forbes - Security
Forbes - Security
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
G
GRAHAM CLULEY
K
Kaspersky official blog
W
WeLiveSecurity
A
Arctic Wolf
TaoSecurity Blog
TaoSecurity Blog
Recorded Future
Recorded Future
AI
AI
T
The Blog of Author Tim Ferriss
宝玉的分享
宝玉的分享
K
KPMG report finds enterprise disconnect between AI and its ROI | CIO
Last Week in AI
Last Week in AI
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
CTFtime.org: upcoming CTF events
CTFtime.org: upcoming CTF events
雷峰网
雷峰网
GbyAI
GbyAI
S
SegmentFault 最新的问题
N
News and Events Feed by Topic
C
CXSECURITY Database RSS Feed - CXSecurity.com
Google Online Security Blog
Google Online Security Blog
博客园 - Franky
罗磊的独立博客

博客园 - BearOcean

const 和指针 C++ 下啥时候用struct, 啥时候用class C++ 和 Java 中的变参 解决站点关键数据,状态数据,无须持久化数据的一些思路 BS程序代码与安全与基本攻击/防御模式 Struts 实现的I18N Ant 阅读笔记 进度,效率,与个人事务管理 Personal Task 1.0 MySql与Java的时间类型 数据挖掘概述 解决Thread 的关闭问题和参数传递时想到的办法. Command 模式 .Net标准控件与自定义控件(2) ToolTipButton 内网聊天工具FreeChat 2.0 FreeChat 2.0 ...大改 模型和架构 局域网聊天工具FreeChat 1.0 开发日志 内网聊天工具FreeChat Beta 为Socket写的附加方法 .Net 事件
LOG.ZS.0001.基于Freetype的游戏字体渲染优化思路
BearOcean · 2015-02-24 · via 博客园 - BearOcean

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 , 总的来说可能会增加大量复杂度。

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

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

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

嗯,嗯,明天开始编码。

现在先去看行尸走肉