逆向:程序研究/AT1/字体例程
AT1的字体例程目前仅研究了主显示用的主字体,对于其他(战斗字体)不甚了解。即使是主字体,目前也仅跟踪到一个缓冲区,对更细节的显示部分并不了解。
AT1的主字体,是24*24,4bpp的灰度位图字体。显示时,字体例程会对其缩放。
取字例程
主取字例程,首先将编码和一个缓存区中的编码数组(int32)里的编码比较。如果没有取到,那么就调用另一取字例程,从字库中取字,复制到缓冲区中。
经后续分析,根据该例程名字(FontMake),可猜测:为了和FontDisp(Tim类图片字体显示例程)适应,这里实际上是将文字画进了一个内存中的“TIM文件”,然后再调用的FontDisp显示。
从字库取字的例程大约工作方式如下:
index = get_index(encode) ptr = texture_base + 24 * 24 * 0.5 * index # 24*24, 4bpp copy_to_cache(ptr)
get_index是一个函数,它在字库描述字符串中比对传入的编码encode,并返回比对成功时的字库索引。
textrue_base是字库基址。这个基址会因字体的变化而变化。
字库索引获取例程(Debug:FontMakeGetFontListPosition)
ABI
参数
a0: 要查询之编码 a1: 要查询之字体编号 gptr_1(char * fontlist[10]): 字体描述字符串(FontList)指针列表
动作
返回v0: 查找到的文本编码在字体描述字符串中的索引(以二字节组为单位)。
伪代码
ptr = texture_description i := 0 while *ptr <> 0 if *ptr = (encoding & 0xff00) >> 8: ptr += 1 if *ptr = encoding & 0xff: return i else: ptr += 1 end; else: ptr += 2 endif; endwhile;
encoding是传入的要获取的字符编码。
texture_description是字库描述字符串的基址。
字体选择器
通过内部控制或控制符FD(D是一个十进制数字,如F0、F1等),可以改变字体。每个字体有独立的字库描述字符串,和字库地址。分别以两个数组存储(一般挨在一起)。
需要注意,每个Font对应一个自己的缓冲区。代码分析发现,GUST如果本来设计了两个字体,那么大概率会事先初始化两份缓冲区(在全局变量中)。否则其他缓冲区(画布)皆不存在。在AT1中,即使设定了第二个字体,由于缺乏缓冲区并不能成功画出第二字体。
Debug:FontMakeSet
预览代码内存13AB54。研究不足。其检查缓冲区并调用无名例程(上取字例程)。
该例程对字体的使用情况进行计数。推测在从缓冲区删除字体时会根据此计数器动作。
Debug:FontDisp
研究不足,预览代码内存13C11C。根据AT显示逻辑,该代码在文本显示时每次渲染循环皆调用。其a0作用未明,且所指结构体使用位置较广。破坏该结构体数据会引发渲染异常(全屏)、DMA错误等多种错误,并使游戏(和模拟器)崩溃。
a1指向一字体显示控制结构体。调控包括文字颜色、文字底色等多种参数。结构体已经探明的结构参数如下:
+0 +1 +2 +3 +4 +5 +6 +7 +8 +9 +A +B +C +D +E +F 0x000 str_ptr | ukn... ... 0x100 ukn... |w |h | ukn...
其中,str_ptr是指向要显示的字符串的地址。
其中,w是字体宽度(单字),h是字体高度(单字),对话框的典型值是0x120,美版的值是0x100。这个值的单位依然是未知的。
其他
Debug:
- FontDispSetXY 13C3F8
- FontDispCountLine 13C8E4
- FontDispTagExec 13D1E8 控制符执行?