HGE引擎学习笔记-字体

4 Comments

1.精灵

      精灵(hgeSprite)是HgeHelper中实现的一个用得非常多的类,很多更高级的模块也基于该类,包括字体,所以在详细阐述字体之前,先说说它。

      hgeSprite对纹理渲染进行简单的封装,它通过一个纹理句柄和区域参数进行初始化,不过底层的渲染参数仍旧基于hgeQuad,见hgeSprite 下列成员函数:

void	Render(float x, float y);
void	RenderEx(float x, float y, float rot,
		float hscale=1.0f, float vscale=0.0f);
void	RenderStretch(float x1, float y1, float x2, float y2);
void	Render4V(float x0, float y0, float x1, float y1,
		float x2, float y2, float x3, float y3);
 

      hgeSprite提供了更为丰富的属性Get/Set,以及更为高级的渲染方式。包括对纹理按比率放缩,旋转,任意矩形放缩和任意四边形放缩。

 

2.字体

      字体(hgeFont)实现基于 hgeSprite,和普通的UI字体不同,HGE中字体实际上是贴图,而这些图片这通过HGE自定义的字体文件提供,后缀为fnt,可以通过HGE官方提供的工具生成。

2.1.字体使用

      HGE字体使用相对简单,不过和其他很多游戏库一样,中文支持是个麻烦。默认的用法如下:

//创建字体对象
HgeFont* fnt=new hgeFont("font1.fnt");
//绘制字体
fnt->printf(5, 5, HGETEXT_LEFT,
	"dt:%.3f\nFPS:%d (constant)",
	hge->Timer_GetDelta(),
	hge->Timer_GetFPS());
//销毁字体对象
delete fnt

      当然在printf之前,也可以设置很多常用的字体参数,如颜色、大小、字距、alpha等。不过不支持字体,所以如果希望使用多个字体,可以定义多个字体文件,并且分配多个 hgeFont实例。详细的字体参数配置见 hgeFont类。

2.2.字体定义

      HGE一个字体包含两部分,一个字体配置文件(.fnt),另一个是字体字模文件(.png)。之所以使用png可能是该格式支持alpha通道吧。

      fnt文件定义了匹配的字模图片文件,以及每一个字符所占用的区域。一个典型的英文字体配置如下:

[HGEFONT]

Bitmap=font1.png

Char=” “,0,0,8,27,0,0

Char=”!”,8,0,5,27,0,0

Char=”"”,13,0,9,27,0,0

Char=”#”,22,0,13,27,0,0

      很显然这种“字体”和点阵字体差不多,所以如果放缩太多容易造成马赛克或者走样。

2.3.字体渲染

      前面提到, hgeFont基于 hgeSprite。实际上,渲染字体就是根据字符序列获得匹配的字模,然后做变换(放缩、旋转等)、Layout,最后通过 hgeSprite来渲染。

      hgeFont使用成员 hTexture存储纹理句柄,而成员letters[256]则存储“256”个字符。这些成员在构造函数中被初始化。具体的渲染操作在函数hgeFont::Render中实现,在那里还包含简单的Layout。

2.4.中文支持

      现在网上有很多牛人提供了中文支持解决方案。说起来中文支持原理很简单,不过很多细节很难把握。

      因为HGE字体渲染使用“点阵字模”,所以自动生成一张包含中文的字模就可以了。不过有几个问题:

  1. 汉字不和ascii码一样就那么几个(我是不知道确切有多少个汉字的),所以如果把所以汉字都贴出来会不会很大,效率会不会受影响,一张图片能不能容得下。而如果只保留常见字,那这个“度”怎么把握?

  2. ascii的索引非常方便,而且效率非常高,可是中文首先字符编码有多种,有些字符编码还是变长,所以对字符作一个好的索引比较麻烦。特别是只取部分汉字时。

  3. 正因为汉字特别多,所以必须有一个自动化的工具生成字模图。

      当然HGE默认的字体渲染框架对于中文并不一定是最合适的,我们完全可以对其源码做适当的修改(甚至重写)已获得更高的性能。

4 Comments (+add yours?)

  1. 圣斗士
    八 27, 2010 @ 15:50:56

    字体怎么弄的呢,我读取一个字体文件(png 对应的xml配置文件),这个格式和hge的字体格式差不多,描绘某个字体在png文件中的位置,以及显示的时候左右缩近值。 一个font 类作为一个基础的工具类,然后上面架设一个 fontManager 来管理,以防生成多个相同的 font。 实际上在写文字的时候,是将一个一个的字的图片贴上去,这样是不是有损效率?

    回复

    • KingQiu
      八 28, 2010 @ 10:03:32

      这倒不至于,好多游戏都这么干,有两点:
      1.图片仅仅在第一次才会从磁盘中Load,以后就从内存中刷
      2.DX使用硬件加速,速度还是够快的

      回复

  2. Caphone_2009
    七 15, 2010 @ 09:58:42

    看了上面文章的描述,首先纠正个问题:sprit 是 spirit吧
    你上面说的HgeFont实际上是PixelFont或者说是ImageFont,这种还是比较局限性的。对于一些ASCII没啥问题,数量少,对于中文 日文来说就麻烦。
    利用freetype等字体库,可以对任何字体处理,而hgeFont的图片字体应该定位为特殊效果的辅助字体。另外freetype渲染出字体纹理后,处理方式和hgeFont自身的处理应该是无缝的,因为前面你定义字体也是定义一个编码和对应纹理位置信息。
    最后还有一点,字体渲染索引一般是基于Unicode编码,现在一般字体都有基于Unicode索引的,freetype有个打开的fontface有个属性可以查询。

    回复

    • 邱金武
      七 16, 2010 @ 09:53:36

      呵呵,关于第一个问题,文中没有sprit,你应该指的是单词hgeSprite中的部分吧,这个词是HGE官方源码中的一个类。
      第二个问题我也一直纳闷,我也问过公司的同事,不过貌似很多游戏都是直接用贴图来做字体而不是用freetype等字体引擎动态生成字模,不知道是不是基于性能的考虑。毕竟这种方法优点很多除了有点耗CPU。游戏引擎和普通的2D引擎如skia、cario还是有一些不一样的。搜了下网上的实现都是这么弄的,通过字体引擎生成静态字模放到游戏中用。

      回复

Leave a Reply