前提知识:

任天堂游戏系统的画面分辨率是256*240像素,基本的显示单位是tile,包含8x8=64个像素

根据电视机的制式不同,NTSC制式只显示256*224,也就是32x28个tile,画面的第一行以及最下方一行的tile是不显示的

PAL制式完整显示32x30个,SMB是以NTSC制式开发的。

【SMB源码解析系列】——004.AreaParserTaskControl行列绘制控制程序-LMLPHP

AreaParserTaskControl是一个比较核心的程序,其下关联的子程序树完成了几乎全部的的游戏画面绘制工作。

从截图中我们可以看到,这个函数主要是用来循环调用另一个处理程序AreaParserTaskHandler,由变量AreaParserTaskNum控制循环次数。

当AreaParserTaskNum等于0时,会将ColumnSets减一,表示绘制完成1列画面(这里的一列具有4个tile宽度,每行也是4个tile,实际上AreaParserTaskHandler就是绘制了一个4x4大小的tile区域)。

ColumnSets减一之后结果是负数的话就会被bpl指令识别,程序跳转至OutputCol,这里总共绘制了12列,也就是32+16=48个tile宽度的一屏半画面。

【SMB源码解析系列】——004.AreaParserTaskControl行列绘制控制程序-LMLPHP

AreaParserTaskHandler中则是调用了名为AreaParserTasks的例程树,AreaParserTaskNum会在一开始被赋值为#$08,也就是说AreaParserTaskHandler会被调用8次。

(开头说到SMB是NTSC制式,只会看到28行的tile,4x7=28,至于第8次是为了什么会在后面提到)

我们可以从3050行看到,AreaParserTaskNum是被递减的,并且作为JumpEngine的入参,因此我们得知AreaParserTasks中的例程是从后向前调用的,树中的8个函数刚好每次循环调用一个。

AreaParserTaskNum中的值递减至0时,3052行的RenderAttributeTables最终被调用,从名字中可以看出来这是用来填充属性表的,

侧面说明执行一次AreaParserTasks就是绘制了一个属性表字节对应的4x4=16个tile的屏幕区域(关于属性表命名表之间的关联关系留待以后说明)。

SMB的地图数据是预先压缩好的,AreaParserCore程序用于将这些数据解压(通过ProcessAreaData函数),然后写入到MetatileBuffer(通过RenderSceneryTerrain函数)

第一次调用RenderAreaGraphics都会根据MetatileBuffer中的值,将绘制4x4的tile区域左上方的tile,第二次绘制左下,所以IncrementColumnPos函数会切换绘制目标到另一侧,

一次通过RenderAreaGraphics绘制右上,右下的tile,再次通过IncrementColumnPos切换绘制目标到左侧,待下一次tile绘制。

对以上的主要流程有了了解之后,我们再来详细说明AreaParserCore、RenderAreaGraphics、IncrementColumnPos的具体内容

05-27 05:48