逆向:程序研究/AT1/字体例程

来自歌颂之丘
星云nebulas讨论 | 贡献2024年2月8日 (四) 11:31的版本 (星云nebulas移动页面逆向:AT1/字体例程逆向:程序研究/AT1/字体例程,不留重定向:​文字替换 -“AT1/”替换为“程序研究/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 控制符执行?