Cross Sections - brunovalads/yoshisisland-disassembly GitHub Wiki

Yoshi inside the cross section in 1-2: overlay turned transparent Yoshi outside the cross section in 1-2: overlay turned on
Cross sections are graphical overlays over terrain to hide the contents inside, giving a "cavelike" effect. They can be found in stages 1-2 and 2-2, for example. The overlays turn transparent when Yoshi enters the cave area, and they turn back on upon exit (with a brief transitional period).

The overlay is on BG3 in 16x16 tile mode. Only BG3 tileset # $0A can activate them. If this is indeed the tileset, then they are loaded in on a per-column or per-row basis. That is, as each MAP16 column/row is spawned in, along with it, cross section tiles get loaded in as well. The routine at $108C9A takes care of this process; the first two conditions it checks are:

   LDA $013E                                 ; $108C9A |\
   CMP #$0A                                  ; $108C9D | | BG3 Tileset $0A
   BEQ .check_new_spawn                      ; $108C9F |/  (Cross section)

 .ret
   RTL                                       ; $108CA1 | if not, return

 .check_new_spawn
   LDA $77                                   ; $108CA2 |\  if neither new column nor
   ORA $79                                   ; $108CA4 | | new row has been spawned,
   BEQ .ret                                  ; $108CA6 |/  return

$0077 and $0079 are flags that say "a new MAP16 column has been spawned", or row, respectively. Basically, when a new piece of the stage loads, also keep these cross section tiles synchronized to that as well.

Much like $700DAA and $700E2A, which hold VRAM tilemap information for the most recently loaded MAP16 column & row, the $702604 and $702644 tables hold tilemaps for the most recently loaded column & row of cross section tiles. In fact, these MAP16 column & row tables are used as a basis to govern which cross section tiles to display in BG3. The game iterates through both MAP16 and cross section new column/row tables simultaneously. Since BG1 foreground is 8x8 tiles, and in this context our cross section BG3 is using 16x16 tiles, this means that the game must iterate twice the amount when going through the BG1 8x8 tiles to move on to the next tile in the column/row. Since there are 4 8x8 tiles per BG3's 16x16, which one of the 4 does it use as the basis? The top left 8x8 tile out of the 4 in the MAP16 tile is the one used to govern which cross section tile to display.

First, the game reads the top-left tile's value, and masks it to get only the tile number:

   to r10                                    ; $08BC50 |
   add   r8                                  ; $08BC51 | r10 = $2644 + tile
   ldw   (r1)                                ; $08BC52 |\ r11 = load top left 8x8 tile
   move  r11,r0                              ; $08BC53 |/ from new row table
   and   r3                                  ; $08BC55 | mask tilemap to get tile # only

Then it tests whether the tile # is in between $0180 and $0200, and if not, load $01CE (which is just a blank tile). This is done because not every tile needs a cross section overlay, only some. This is the range that needs them:

   bcc .store_blank_tile_row                 ; $08BC57 | | if tile > $0200 or tile < $0180
   sub   r5                                  ; $08BC59 | | then load $01CE (blank tile)
   bcs .store_tile_row                       ; $08BC5A | |
   from r9                                   ; $08BC5C |/

If we are in fact within the proper range, then the tile number for the cross section is determined by the MAP16 tile number masked with $007F, so the first 7 bits. We also take the vertical/horizontal flipping information directly from the MAP16 tilemap entry, leaving us with a tilemap like this: vh1000010ttttttt, where v and h and the first 7 bits of t come directly from the corresponding top-left 8x8 MAP16 tile, and the rest is priority bit set and palette = 000:

   and   r6                                  ; $08BC5E | | new row tilemap entry
   bra .store_tile_row                       ; $08BC5F | | & $C07F | $2100
   or    r7                                  ; $08BC61 |/  vh1000010ttttttt

This tilemap information gets stored to the aforementioned cross-section tables, $702604 and $702644, for the entire new column or row. From there, they get added to the general-purpose DMA queue at $7E4800 to be DMA'd into the proper column or row of BG3 tilemaps, which begins at VRAM address $3400.