掘金 阅读 ( ) • 2024-07-02 11:58

1.  前言

OpenGL 对于文字的绘制以及字体的操纵提供了低层次的支持,即位图字体。每个字形根据他们的编号被放到位图字体中的确切位置,在渲染这些字形的时候根据这些排列规则将他们取出并贴到指定的位置。这种方法相对来说很容易实现。

2.  基于 FreeType 的字符渲染流程

FreeType 是一个能够用于加载字体并将他们渲染到位图的软件开发库。它具有开源、跨平台、占用空间小、支持多种字体文件的读取和操作、效率高等特性。

2.1 基于 FreeType 的位图数据生成

FreeType 获得位图数据的过程依次为初始化库、载入字体文件、设置字体尺寸、由字符编码获得字形索引、装载字形和获取位图等,其具体步骤如下:

(1)初始化库。使用 FT_Init_FreeType 函数初始化库,生成类型为 FT_Library 的 Library 对象。

(2)载入字体文件。一个字体文件可能对应若干个字体外观,以字体外观的索引号来获取需要加载的外观。使用FT_New_Face 函数可以从一个指定文件载入字体,使用 FT_New_Memory_Face 函数则从一个内存地址处载入字体。将获得的数据赋给类型为 FT_Face 的 Face 对象,方便后续数据的获取。

(3)设置字体尺寸。载入字体并获得 Face 对象后,首先要使用 FT_Set_Pixel_Sizes 函数设置像素尺寸。如果使用的是可伸缩字体格式,可以将 size 设置成任意合理的值;对于固定尺寸格式,若是设置的 size 不在 Face 对象的可使用尺寸数组中,则会引发错误。

(4)字符编码到字形索引。字形索引是字体文件内部用来查找字形的索引。可以通过字体文件提供的字符映射表来将字符编码转换成对应的字形索引。通常一个字体文件会包含多个字符映射表,以提供对多种常用的字符编码的支持。Face对象charmaps 表记录了当前字体提供的字符映射表,可以使用预定义的一些枚举值来调用 FT_Select_CharMap 函数来选中某个字符映射表,也可以手动遍历charmaps,以符合要求的 charmap 调用 FT_Set_CharMap 来设置字符映射表。完成字符映射表设置后,使用FT_Get_Char_Index函数在字符映射表中,找到特定字符编码对应的字形索引。

(5)装载字形。一旦获得了字形索引,便可以通过FT_Load_Glyph 函数装载对应的字形映像。对于固定尺寸字体格式,每个字形都是一个位图;对于可伸缩字体格式,则使用轮廓的矢量形状来描述每一个字形。字形映像存储在字形槽中,一个Face对象只有一个字形槽,所以每次只能获取一个字符对应的字形。

(6)获取位图。对于固定尺寸的字体格式,由于获取到的字形是位图,可以直接使用;对于可伸缩格式的字体,装载的是一个轮廓,必须通过 FT_Render_Glyph 函数将轮廓渲染成位图后才可以使用。获取到位图数据之后,可以通过字形槽的bitmap属性来访问位图数据,bitmap_left属性和bitmap_top属性用来指示起始位置。

图片

位图数据的流程图

2.2 字符纹理的创建与绘制

字符纹理的生成与纹理贴图主要依靠OpenGL函数实现,过程为纹理使能、纹理参数设置、字符纹理生成、纹理贴图和纹理禁止等,其具体步骤如下:

(1)纹理使能。纹理使能过程为使用 glGenTextures 函数创建纹理 ID,再使用 glEnable 函数打开纹理开关,然后使用glBindTexture 函数将纹理 ID绑定至当前纹理,然后使用设置当前纹理映射功能。

(2)纹理参数设置。使用 glTexParameter*函数指定放大缩小时的过滤方法。

(3)字符纹理生成。根据已获得的字符位图数据,使用glTexImage2D函数生成对应的字符纹理,可以通过参数设定即将生成

纹理的宽、高、RGBA 或 RGB 等参数。

(4)纹理贴图。使用 glTexCoord 函数和 glVertex 函数结合实现纹理坐标的映射。

(5)纹理禁止。使用 glDisable 函数关闭纹理开关。

图片

纹理创建与绘制流程图

3.  缓存机制

3.1 位图缓存机制

位图数据缓存用于存储已加载文字的位图数据对象。位图数据缓存的大小在程序初始化时根据字体文件中字形的数量进行设置并将内存全部初始化为 0。位图数据缓存以字符编码为索引存储或查找位图数据对象。位图数据对象包括该文字的位图数据、其字符纹理是否在大纹理中的状态值、在大纹理中的位置信息等属性。位图数据对象的状态值有 0、1 和 2 三种状态。值为 0 是初始化的值,表明文字没有被绘制过,位图数据对象中的位图数据和位置信息是无效的;值为 1 时,表明文字被绘制过且字符纹理在大纹理中,位图数据对象中的位图数据和位置信息有效;值为 2 时,表明文字被绘制过但字符纹理在纹理更新时被替换掉了,位图数据对象中的位置信息是无效的,但位图数据有效。通过位图数据对象的位置属性可以在大纹理中获取需要的字符纹理或在位图数据缓存中获取需要的位图数据,方便文字绘制时相关数据的直接调用。

3.2 纹理更新策略

大纹理一般是正方形,用两个属性值表示大纹理的某一个坐标,用于当一个字符纹理要存储到大纹理时的起始位置。同一个字体指定字体大小的所有字符生成的字符纹理均使用同一个宽高,字符纹理以起始位置坐标存储于大纹理中,然后起始位置坐标以字体大小为步长增加。

图片

字符纹理存储示意图

4.  整体流程

通过以上设计完成文字的双缓存快速渲染,使得文字的渲染效率得到提升。

图片

整体流程图

-End-

作者丨double 进