黃爸爸狗園

本園只有sanitizer,沒有狗籠

0%

GBA圖形處理邏輯模擬 - Background Map

cover

GBA的VRAM中有數塊特殊的區域用來描述在一個BG中如何排列tile,我們將其稱呼為BG map memory,本文將會詳細說明其格式與特點

Map data format

Map data內部紀錄了渲染一塊tile所需要知道的資訊,其格式根據BG為Text或者Affine會有所不同:

  • Text BG

    欄位功能描述如下:

    • Character name
      • 雖然叫做name,但實際上是一個offset,當你從BG_CNT上計算出tile block base之後,假設BG_CNT上標明這是一個4bpp tile,則此map data所對應的tile data的address為:
      • base block addr + chara. name * 0x20(4bpp的一個完整tile size)
    • 假若是8bpp,則tile data會位於
      • base block addr + chara. name * 0x40(8bpp的一個完整tile size)
    • 有關tile data詳見GBA圖形處理邏輯模擬 - Tile format
  • Affine BG

    對,沒錯,真的就只有Character name,Affine BG的tile是強制256色的,考慮到Affine BG是利用仿射矩陣直接將screen pixel映射到map memory上,這樣的設計是最合理的

    • 因為tile一定是0x40,所以tile data的位置算法就是8bpp算法
  • Horizontal flip flag

    • 此tile在渲染時是否要左右顛倒,我這裡是直接將讀出來的tile data做inverse
    • 考慮tile是4bpp的情況
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      if (xInverse) {
      // Swap the nibbles of each byte.
      buf = (buf & 0x0F0F0F0F) << 4
      | (buf & 0xF0F0F0F0) >> 4;

      // Swap the bytes of each byte pair.
      buf = (buf & 0x00FF00FF) << 8
      | (buf & 0xFF00FF00) >> 8;

      // Swap the byte pairs.
      buf = (buf & 0x0000FFFF) << 16
      | (buf & 0xFFFF0000) >> 16;
      } // if
    • 8bpp會比較簡單
      1
      2
      3
      4
      5
      6
      7
      8
      9
      if (xInverse) {
      // Swap the bytes of each byte pair.
      buf = (buf & 0x00FF00FF) << 8
      | (buf & 0xFF00FF00) >> 8;

      // Swap the byte pairs.
      buf = (buf & 0x0000FFFF) << 16
      | (buf & 0xFFFF0000) >> 16;
      } // if
  • Vertical flip flag

    • 此tile在渲染時是否要上下顛倒
  • Color palette

    • 如果BG_CNT有聲明是4bpp,則最後tile在繪製時所參考的palette number就會是這個欄位所描述的
    • 你可以把此欄位理解成row number,假設palette number是4,那tile就會變成全黑(因為tile 4所有16色都是黑色)

Virtual screen

Map memory基本上就是一塊由map data以二維排列而成的記憶體區塊,我們可以回顧一下這張表格:

其中我們可以注意到Character format BG screen下有一個size的欄位,裏頭描述幾種螢幕大小組合,但可以確定的是都與我們所知道的GBA螢幕大小240*160不同

這就是所謂的Virtual screen機制,我們可以把他想像成我們利用一個240*160的取景視窗,在一個很大的虛構區域內移動,接下來我們要來討論兩個重點:

  1. 虛構區域的大小
    • 我們能夠移動的虛構區域大小是依靠BG_CNT中的Screen size控制的,其大小如下表所述:
    • 圖表中明確提到了Text/Affine的狀態下,map data的尺寸與記憶體占用皆不同
  2. 如何移動可視範圍
    • 我們在確認Virtual screen的大小後,下一步自然就是要把取景範圍移動到我們想要的地方,這一個步驟在Text BG與Affine BG下的操作方式並不相同:

      • Text BG: 我們需要調整HOFS以及VOFS兩個register來移動取景範圍的左上角座標,如果這兩個暫存器的數值超過的virtual screen的尺寸的話,真正對應到的數值將會被 %screen size

      不同的Screen size,移動時看起來會像是這樣

Address formula

最後附上一個Text BG計算某一個screen pixel,其所在的tile對應到那一個map data的計算公式:

  • Physical screen X, Y = Sx, Sy
  • Virtual Screen Width, Height = Vw, Vh
  • Viewing area X = (Sx + HOFS) % Vw = S_vx, Viewing area Y = (Sy + VOFS) % Vh = S_vy
  • Screen Base Block in BG_CNT = Sb
  • map data address = 0x0600'0000 + (0x800 * Sb) + {((Vw / 8)*(S_vy / 8)) + (S_vx / 8)} * 2
    • 每一個tile為8*8,所以S_v(x|y) / 8是為了把pixel XY轉換為tile XY
    • 最後*2是因為Text BG每一個map data為2 bytes