我们离正确画出第一张图只剩下调色板了,让我们继续吧
本系列已完结,以下是各章节说明,17 之前是 dos 版相关,之后是 2001 版:
我们知道每种颜色由红绿蓝三种颜色混合而成,这三种颜色值由六位二进制数字设定,
所以取值范围是 00h
到 3fh
,红绿蓝三色的数值确定后,
我们就可以知道这是什么颜色。由于程序同屏显示的最大颜色数是 256,
所以内存中一定会存储这 256 种颜色的三原色数值。
我查阅了一些 VESA 的资料,设置调色板基本还是靠调用寄存器, 但是这部分指令在日志中却没有找到, 所以我推测可能程序已经提前映射好了调色板的地址, 可以直接修改调色板而无需再调用寄存器,因为我的 cpu log 是从游戏中记录的, 而不是从头完整记录,从内存看来是不好下手了,我们看一看文件中是否有新的发现。
我们通过搜索第一张图的读取内容,可以得知,图片保存的起始位置是 00071dh
,
好巧不巧, EVENT.PAT 00033dh
附近有这样一串数字:
因为前面有几行 00h
,所以这个位置还比较明显,00071dh
正好是图片的起始位置,
而他的前面又是 3f 3f 3f
,看到这里我们可以会心一笑,这是白色。
所以调色板到 033dh
(不含)结束,256 色的调色板应该会占用 300h
(注意是 16 进制)个字节,那么,调色板的起始位置应该是 003dh
:
第一个颜色是 002100h
,虽然跟我预期第一个应该是黑色 000000h
(位置 003ah
)
不太一致。简单扫了一下数据,没看到大于 3f
的数值,
那么这段数据应该就是调色板了,我们画一画试试:
人物是正确的,但是背景色一塌糊涂,难道调色板真的是从 003ah
开始,
虽然我不太相信,不过谨慎起见,从 003ah
画一次也不难:
这个错得就更多了,所以应该还是 003dh
开始,
而且程序要么对调色板进行了一些特殊处理,要么就是我们找错了调色板。
有个事情顺带提一下,之前在分析大富翁三时也讲过,因为现在我们表示颜色一般是用 8 位二进制显示了, 也就是 0-255,6 位颜色是 0-63,所以我们需要将 6 位颜色「放大」到 8 位, 不然画面会非常暗。
前面也说了,直接通过寄存器的方式去查日志没有什么结果,所以这次我们搜搜看,
程序读取调色板后是如何处理的,我们在日志中搜索 int 21.*3f
前面三条指令一共读取了 01b342h
个字节,回忆我们上一期的内容,
第一张图片读取的长度是 111426
,也就是 01b342h
,所以前三个读取了完整的图片,
那么为什么后面又读取了 150h
个字节呢。
我们回到 EVENT.PAT 的 00033dh
的位置:
在这里我们还能发现更多对后续有帮助的信息,
比如 1d 07 00 00
其实是第一张图的起始位置,80 02
其实是图像宽度,
67 01
是图像高度,接下来这个 af bb 01 00
很可能就是第二张图的起始位置了,
这样我们可以算出第一张图的长度,01bbafh - 00071dh = 01b492h
,
对比图片长度 01b342h
,正好多了 150h
字节,
我们看看这 150h
个字节到底存了什么:
我们又看到了 3f 3f 3f
,看来这 150h
个字节就是我们要找的另一块调色板,
不过另外一个问题接踵而来。
150h
换成十进制是 336,只有 112 种颜色,那么如何跟第一块调色板合并,
这就变成了我们新的问题,一个近乎直觉的做法是:因为第一块调色板是完整的,
而且后面用 0 来填充了很多,所以这 112 色是第一块调色板后半块的补充。
这样的话,我们需要用第一块调色板的前 144 种颜色加上这 112 种颜色,
组成一块新的调色板,我们画画看:
还是不对,那么是不是应该把第二块调色板放在前面呢,也不对,这里就不再放图了。
我们回到程序读取第二块调色板的日志:
0277:00000D0C int 21 EAX:00003F50 EBX:0001000A ECX:00000150 EDX:1BF28180 ESI:00000070 EDI:0000578C EBP:00005738 ESP:00005734 DS:04FF ES:028F FS:0000 GS:0000 SS:028F CF:0 ZF:0 SF:0 OF:0 AF:0 PF:1 IF:1
内容被读取到了 04FF:8180 的位置,然后搜索 rep.*8180.*04ff
,
看有没有再被复制到哪里:
0277:00001D10 repe movsb EAX:00030150 EBX:00005800 ECX:00000150 EDX:00000287 ESI:00008180 EDI:000022F8 EBP:0000580E ESP:00005800 DS:04FF ES:0287 FS:0000 GS:0000 SS:028F CF:0 ZF:0 SF:0 OF:1 AF:1 PF:1 IF:1
复制到了 0287:22f8
,那么索性我们搜程序有没有复制 300h
个字节,
我们在日志中搜 rep.*cx:....0300
从 0287:21a8
向 028f:556e
复制 300h
个字节,看上去和上面的内存地址有交集?
我们用 22f8h
减去 21a8h
,正好也是 150h
,这下似乎一切就明朗了,
在第二个调色板前面,还有 112 个颜色,我们也很好猜这 112 个颜色从哪里来。
调色板似乎不是分两部分,而是三部分:
00003dh
开始,虽然完整定义了全部调色板,但是仅有前 112 色用于绘制人物。最后,我们再次合并两个调色板,验证下我们的结论吧: