An PS2DEV Tutorial #2d
Fonts and Text in 2D
Version 1.0, 2002/03/23 - Tony Saveski (dreamtime), t_saveski@yahoo.com
引言
终于是指南2d了,我原本以为永远也写不到这来的。学完这份指南之后,我们就有了一个相当完整的2D图形库了。这份指南是关于位图字符和向屏幕打印文字的。我不会涉及TrueType字体和向量字体,这些留给其他人去写吧。
我们所需要的PS2的图形库都已经在前几份指南中完成了,这样创建字体和文本就非常简单,但是需要增加不少东西。我将主要涉及的主题是:
*创建一个位图字体文件
*装载一个字体
*使用这种字体写文本
*使这些文字更漂亮
我将告诉你可以使用这些图形库做些什么,以及我将做些什么。
创建字体
首先我们要做的就是创建一个包含所有我们需要的字符的图片。我把这个图片的大小设定为256x128,我们马上就会在代码中看到它了。
有不少方法可以创建图片。我首先尝试使用Photoshop,创建一幅图片resources/verdana.bmp。你也按如下步骤创建一幅图片:
*创建256x128像素的位图,设置背景色为黑色
*选择文本工具,选择前景色为你喜欢的颜色,背景色为黑色,选择字体,然后依次写出你需要的每一个字母。确保每一个字母之间有一定的空隙。
*确保antialiasing和blending选项都被关掉,尽管打开后字体要好看的多。否则在你自己的程序里如果不使用黑色作背景,那会变得非常难看。
*如果你对你的图片很满意的话,就将它保存为24位的位图吧。这样就可以用BMP2C转换成我们需要的C代码,就像之所做的一样。
装载字体
在使用之前,我们需要将字体装载到GS内存中去。我们可以使用gs_load_texture()来完成这一工作,不过首先都分配一个内存地址给它。在g2_init()中,你可以看到我已经在完成两个帧缓冲分配之后,全屏图片缓冲之前,又分配了一个256x128的字体缓冲。
我听到你问这个g2_font_tc是什么东西。它只是一个128x4数组,包含了贴图坐标。我为每一个字符都定义了一个矩形,每一个字符都有由(x0,y0),(x1,y1)的坐标组成的矩形包含了这个字符,如果这个字符在我们的位图字符中不存在,矩形就包含了一个黑色区域,如果是空格字符,矩形就包含一个大小合适的黑色区域。我必须手动的来创建verdana_tc.c文件。
将文本写到屏幕上去
我们得循环文本中的每一个字符,然后获得包含字符的矩形坐标,该坐标即字符在字体位图上的位置,然后向屏幕绘制精灵贴图。绘制的代码和g2_put_image()差不多,我拷贝了一份,以便以后作少许修改。
更好看的字体
如果你现在就运行Demo,你会发现第一条消息的开始部分很好,它只用了对齐了的大写字母。但是这消息的其他部分,那些小写、大写混排的字母看起来就很无序了。我原以为那是由于糟糕的贴图坐标造成的,不过我最后一直回到了检查起先Photoshop输出的字符,才发现问题所在。似乎Photoshop会将有些字符绘制的更高一些,虽然只是一两个像素的区别,但这却导致了我的字体看起来实在糟糕。如果有谁可以告诉我如何让Photoshop不这样做,请尽快告诉我。
有一种解决的方法就是,确保每一行中都有字母“j”,它有完整的高度,可以让每一行都有固定的高度。但这实在不是一个好方法,而且浪费GS内存。我也需要一种更好的生成贴图坐标的方法,使用手工的方式生成实在太浪费时间了。
搜索了一下互联网后,我发现了一个不错的工具,Thom Wetzel做的”Bitmap Font Builder”。它可以在http://www.lmnopc.com下载。你所需要的就是选择你的字体,设置一下属性,选择256x256为你的位图大小,这样你就可以有一幅可以在PS2上使用的位图字体了。这个程序会在这幅位图上生成两种字体,所以我用Photoshop截取了一半。
下一步我们需要生成贴图坐标。这不难,因为Thom的程序生成的每一个字符都占有相同的大小。所以只要知道位图是256x128大小,一共有16 x 8个字符,很容易就可以计算出每个字符的贴图坐标。我创建了一个叫做fixed.c的文件,它可以处理Bitmap Font Builder生成的图片。你只需使之让字符间的间隔大小合适,使之好看一些(有时间隔为负数时更好看)。
如果是使用定宽字体(譬如courier-new),那完成上面的工作就已经让你很满意了,但是有时我们需要使用变宽字体,那该怎么办?最简单的办法,我想就是告诉Thom的工具对字符向左作调整,然后修改存在的贴图坐标x1,使之有需要的宽度。(实际上这个工具可以输出所有的宽度)。如果有人写了一个可以自动完成这件事的工具的话,一定要告诉我。
我在这份指南中创建了定宽的courier-new和tahoma字体。不要再使用刚才在Photoshop中手工编辑的verdana字体了,重新看看Demo里的新字体吧。
改变字体颜色
最简单的改变字体颜色的方法就是创建一个你所需颜色的位图字体。但是我只到大家都想不更改字体,而在运行时改变字体颜色。我不想使用基于CLUT像素格式的字体,因为现在只想用32位的字体,不想支持两种字体类型。最明显的一种方法就是修改在EE内存中的位图,设置每一个不是黑色的像素为你所需要的颜色,然后装在这份字体到GS内存。我想这种方法更能被接受,也不会太慢(因为你不需要每帧都做这件事),但是我想做更有趣的事,也许是使用GS硬件吧。另一种实现改变字体颜色的方法就是设置 FRAME_x寄存器的FBMASK位段,可只让你需要的颜色通过;将文本绘制为白色,重置FBMASK是所用颜色通过。我试过了,可以工作。
我也思考了一下Alpha混合模式,使GS绘制一种任意的颜色到帧缓冲上,只要Alpha或颜色不为零,就上色。我还不能在短时间内完成这个,但是如果有谁比我更具创造力,可以有办法完成它的话,告诉我。
我实际采用的办法是直接绘制一个巨大的上色的矩形到字体混充上去。我将字体缓冲当作帧缓冲一样处理了,绘制时告诉GS不要在alpha为零的位置绘制像素。通过这种方法,只有使用的字体像素被改成了新的颜色。我将这种方法留给读者了,就当是练习吧。(主要是我的代码中有一些Bug,我还没有找出来,所以没有完成代码,来展示给读者)
让白色字体在我的蓝色背景上看起来不错,看起来花了不少力气。这一定是Square在Final Fantasy中使用这种组合的原因。使用HCI理论去选择文本以及背景字体吧,也要考虑到像我一样的色盲人群哦。(蓝绿色盲)
Blending and Antialiasing
尽管我直到现在只是给你看了讨厌的白色字体,我们可以使用那些更漂亮的位图字体,就像许多Demo和游戏中做的那样。要完成这个目的,我们到回到Photoshop。我不想解释我怎么创建了这些字体(是的,我确实是自己完成的,这个我还能做到J),我已经将PSD文件包含在了resource文件夹里了。你要能够将它做出来,并且能很轻易的修改他们。我做的第一个就是一个简单的字体,填充了渐变色,使用黑色背景,没用使用antialiasing或blending。这就不可避免的有锯齿,看起来很糟。
所以我想让Photoshop做一些antialiasing。这在Photoshop里看起来不错,但是字符边缘的像素与黑色背景作了混合。当我把他们写到一个不同的背景上时,看起来就很糟了。你可以找到我创建的第二个字体/resource/texfont.psd。在第一次的字体基础上,我添加了一圈黑色的边框(实际上是(1,1,1)的颜色,这样在alpha测试中就不会被忽略)。我用Photoshop在黑框的内部作了antialias。你可以看到在Demo里,如果不是很大的话,看起来不错,尽管仍有锯齿的感觉。但是如果是很大的话,看起来还是很糟。所以我只好使用PS2的Alpha混合了。在我做这之前,我需要一种方法获得各像素正确的Alpha值,填充到Alpha通道里。这样我们就需要一个增强版本的BMP2C(原来的只填充0x00或0x80)。我很快的修改了它,使之接受第三个参数,即另一个BMP文件,这个文件即原图片文件的alpha通道。最简单创建Alpha通道位图的方法如下:
*打开字体psd文件。
*只显示背景层和白色的字体层
*将白色的字体颜色改为0x808080(因为在PS2上Alpha的有效范围就是0x00- 0x80)
*将它保存为24位的BMP文件。
就这么简单。你可以在resource/texfont2.psd找到我的例子。
现在检查Makefile,看看是否正确地自动生成代码,饭后运行一下看看结果。
要使用Alpha通道,我们需要作一点小的改动。首先我需要设置Alpha_1寄存器。Alpha_1寄存器可以让你设置Alpha混合函数Count=(A-B)*C>>7+D的参数。这里是各参数:
要使我们需要的效果,需要如下设置:
A = 字体像素的颜色
B = 帧缓冲里的像素颜色
C = 字体像素的Alpha值
D = 帧缓冲里的像素颜色
我已将这些代码放进了g2_init()函数,它只需要做一次。
最后一件事就是告诉GS使用Alpha混合来绘制图形。另外也注意正确的设置了Alpha测试参数,正确的过滤了黑色像素。
结论
有很多方法可以获得我在这片指南里所达到的效果。譬如你可以使用颜色查找表,和使用不同单色像素格式,这样可以结社很多内存空间,还可以很容易的通过修改CLUT改变字体颜色(大概吧J)只要记住我通常都用了最简单和直接的方式,有时也许不是最好的方法。我现在想开始使用完全的32位像素格式了。
这是2D指南的最后一分了。祝愿你们可以得到灵感,并创建一个不错的Demo或者一个游戏。只要当你成功的时候告诉我一声就可以了,因为我想看到一些2D有创造力的东西。如果有谁可以想到使用Alpha通道更多的作用,请告诉我。
我现在一直在对我所写的代码作一些修改,尤其是增强一些绘制不同的图片和字体的函数,使之更能一般化。留意一下http://www.livemedia.com.au或者ps2dev@topoca新闻组的更新吧。
下一步我们去那里呢?我在刚才的五分钟里相处一些有潜力的方面:
*修改绘制字体的模式,从精灵模式改为三角形,让字体可以旋转。当需要漂亮的旋转字体时会很有用。
*生成一些漂亮的位图字图来和大家共享。我是快对Photoshop绝望了,不过也许你们能帮助我。如果你们懒得去手工生成贴图坐标,我可以帮助你们。
*写一个通用的GUI库,我想这不会花太多的时间,也确实很不错。也许从一个现有的直接移植过来会是一个好主意。
*移植一些旧的Amiga,PC,甚至C64游戏到PS2上。写一些关于如何生成等离子、火焰、例子系统等效果的指南。
*写一个游戏,或者移植一个2D(或者伪3D)游戏。
*移植一个模拟器!使用GUI库来选择ROM。Sjeeps的SMS模拟器就是一个例子!我听说ps2dev里的某些人已经在移植MAME模拟器了。
*移植True Type字体引擎到PS2平台上。我直到已经有一些免费的了。
来吧,伸出你的手指,做些什么!!J现在我们一定可以每两周都看到大家的新Demo了。另外我个人也想看到每个人都愿意共享他们所有的代码。否则就没意思了。
我想我下一步会做一个简单的2D的游戏,它只要花上几天吧,会很有意思的。之后,也许要写更多的指南,使用贴图坐标的2D或3D的,或者声音之类的。如果你有什么更想看的,给我点意见吧,多来点e-mails哦,尤其是你有任何意见和建议。
欢呼吧!