32x32 pixel meta tiles and vertical scrolling

Discuss technical or other issues relating to programming the Nintendo Entertainment System, Famicom, or compatible systems. See the NESdev wiki for more information.

Moderator: Moderators

Post Reply
User avatar
DRW
Posts: 2225
Joined: Sat Sep 07, 2013 2:59 pm

32x32 pixel meta tiles and vertical scrolling

Post by DRW »

Imagine you have a game where you decide to store the level data as 32 x 32 pixel meta tiles (i.e. 4 x 4 hardware tiles).
This has the advantage that each meta tile corresponds exactly to one byte for the color attributes.
So, when you write your color attributes data to the PPU, you don't have to keep the old attributes of the entire screen in memory and do complicated bit manipulation to determine what value to write.
Instead, you know: For this 32 x 32 pixel meta tile, you can simply write exactly one corresponding attributes byte into the PPU and you're done.

But now you decide to have the game scroll vertically, like in "Commando".

Vertically, the NES has 30 rows. This means the lower half of your last meta tiles row of the screen is cut off.
Well, fortunately that's not a problem. You can simply draw the missing half to the first two rows of the next name table.

But now we have the problem that the attributes on the new name table aren't aligned with the meta tiles anymore:
Rows 0 and 1 on the new name table are now occupied by the lower half of the last meta tiles from the previous name table. And the next meta tile would be located on rows 2 to 5.
But of course, the attribute values for the new name table are laid out in a way that they are for rows 0 to 3. And for rows 4 to 7.

This means the whole advantage where one meta tile corrsponds to one attributes byte is lost.
Now, you have to keep all 128 attribute bytes in a separate array, so that you can, by bit manipulation, overwrite the bits for rows 0 and 1 while keeping the bits for rows 2 and 3. And for the next rows, you need to calculate what bits to change, so that rows 2 to 5 are written, but rows 6 and 7 stay as they are.


Is there any way around it?

I mean, I could design the level in a way that every eighth row has special meta tile that consists only of 4 x 2 hardware tiles instead of 4 x 4.

Or is there maybe a way to skip the final two rows when scrolling, so that the NES displays row 0 from the lower name table directly below row 29 from the upper name table?
My game "City Trouble":
Gameplay video: https://youtu.be/Eee0yurkIW4
Download (ROM, manual, artworks): http://www.denny-r-walter.de/city.html
User avatar
tokumaru
Posts: 12427
Joined: Sat Feb 12, 2005 9:43 pm
Location: Rio de Janeiro - Brazil

Re: 32x32 pixel meta tiles and vertical scrolling

Post by tokumaru »

30-tile tall name tables combined with 32x32-pixel attribute areas create one of the biggest drawbacks of scrolling vertically on the NES...
DRW wrote: Sat Mar 05, 2022 4:28 pmI mean, I could design the level in a way that every eighth row has special meta tile that consists only of 4 x 2 hardware tiles instead of 4 x 4.
You don't need special metatiles, you can just ignore the bottom half of metatiles used in the 8th row. This will greatly complicate collisions though, unless you use a separate map for collisions where nothing is skipped.
Or is there maybe a way to skip the final two rows when scrolling, so that the NES displays row 0 from the lower name table directly below row 29 from the upper name table?
You can use scanline IRQs for this, but then you're not gonna be able to do other raster effects on the exact scanline where this split happens.
User avatar
DRW
Posts: 2225
Joined: Sat Sep 07, 2013 2:59 pm

Re: 32x32 pixel meta tiles and vertical scrolling

Post by DRW »

tokumaru wrote: Sat Mar 05, 2022 9:33 pm You don't need special metatiles, you can just ignore the bottom half of metatiles used in the 8th row.
Yeah, but still: If you have a bunch of trees standing in a grid, you now also need addititional meta tiles that include "tree bottom, tree top" instead of the regular "tree top, tree bottom".

tokumaru wrote: Sat Mar 05, 2022 9:33 pm You can use scanline IRQs for this, but then you're not gonna be able to do other raster effects on the exact scanline where this split happens.
What do you have in mind? I tried changing the vertical scrolling position in IRQ, but it didn't work. What exactly do I have to do here?
My game "City Trouble":
Gameplay video: https://youtu.be/Eee0yurkIW4
Download (ROM, manual, artworks): http://www.denny-r-walter.de/city.html
Oziphantom
Posts: 1565
Joined: Tue Feb 07, 2017 2:03 am

Re: 32x32 pixel meta tiles and vertical scrolling

Post by Oziphantom »

cheat, shrink the view by 16 pixels( make a hud), so you never show the bottom row. Don't do NES scrolling do Commodore scrolling, where both screens are buffers you flip between.
So given Buffer A and B
Show A
While you shift it 16 pixels in hardware. move the data in Buffer B up 32 pixels manually.
Draw the current bottom row then the next row at the bottom of buffer B
Show B
While you shift it 16 pixels in hardware, move the data in Buffer A up 32 pixels manually.
Draw the current bottom row then the next row at the bottom of buffer A
Show A
... repeat

Or go MMC5 and get 8x8 attributes which makes the problem disappear.
User avatar
DRW
Posts: 2225
Joined: Sat Sep 07, 2013 2:59 pm

Re: 32x32 pixel meta tiles and vertical scrolling

Post by DRW »

I think a HUD will not solve the issue. A HUD covers the bottom part of the screen, but not the lowest tile rows of a name table in a game with free vertical scrolling.
Or am I overlooking something?

Manually shifting the data around: I actually wanted less work for the CPU to do, not increase the work load.

And MMC5, apart from being an expensive mapper, would not solve the problem. I chose the 32x32 meta tiles to save space, not out of a technical necessity. I could just as well use 16x16 meta tiles and keep the attributes map in RAM, circumventing the issue completely. The problem only exists because I‘d like to store my levels in less ROM space and I want to avoid wasting 64 bytes to buffer the attributes.
My game "City Trouble":
Gameplay video: https://youtu.be/Eee0yurkIW4
Download (ROM, manual, artworks): http://www.denny-r-walter.de/city.html
Oziphantom
Posts: 1565
Joined: Tue Feb 07, 2017 2:03 am

Re: 32x32 pixel meta tiles and vertical scrolling

Post by Oziphantom »

A HUD covers which ever side of the screen you want. But the point is a 16 pixel high HUD gives you 16 pixels to scroll on screen without having to cross a nametable boundary. Say you do put it at the bottom, now when you scroll -16 you are seeing the 16 pixels that were hidden by the HUD not "next nametable", giving you 16/vertical scroll rate frames to prepare then next buffer.

However I read the diagram wrong, its showing 4x4 not 2x2 which is how it looks on the wiki. Right so the map has a 16 pixels alignment. I was thinking the issues was you got onto a 8 pixel offset so 24 on nametable and then 8 on the next which is impossible without a MMC5 to handle. So what is the issue?
In that when you cross the boundary i.e 20F8 -> 28C0 you plot the same attribute value on the bottom 16pixels and the upper 16 pixels of the first row, yes it is then split over the byte for the next screen before going back to being "byte aligned" but that doesn't seem to be that much of a big deal, a couple of 4 byte look up tables.
You will have the attributes stored in RAM so you just `AND #$f` on the upper attributes, which still matter, than next set it doesn't matter what you write to the lower half as they won't be visible and will be masked next row plot anyway of which you will be a decent amount of a screen ahead in your plots anyway. We are looking at 16 bytes of data to do this too max.
User avatar
DRW
Posts: 2225
Joined: Sat Sep 07, 2013 2:59 pm

Re: 32x32 pixel meta tiles and vertical scrolling

Post by DRW »

Oziphantom wrote: Sun Mar 06, 2022 4:50 am A HUD covers which ever side of the screen you want. But the point is a 16 pixel high HUD gives you 16 pixels to scroll on screen without having to cross a nametable boundary.
But that's not my issue. My issue is:

If I have 32x32 meta tiles, then I can store the meta tiles and the attributes value together. And whenever I draw the tiles of a meta tile, I can simply update that one attributes value in the PPU.

If I stored my level data for example as 16x16 meta tiles, then I'd need to keep 128 bytes for the attributes in a buffer array because I'd have to use bit manipulation and stuff to update the attribute value of one particular meta tile. That's 128 bytes of precious RAM space for stuff that's on the screen anyway, just because there's no fast way to read out these values live from PPU. (Yes, I know you can read out these values during NMI, but still, it's definitely not ideal.)

However, the advantage of meta tile and attributes alignment goes right out the window when you reach the end of the name table, because vertically, each name table has 7.5 meta tiles of 32x32 pixels.

So, either I have to draw the second half of my eighth meta tile to the first rows of the next name table. Which is not a problem for the tiles themselves, but there goes my attribute alignment advantage and I have to store the attributes in RAM again.

Or my level data in ROM needs to be designed in a way, so that every eighth meta tile is defined as only occupying 32x16 pixels on screen while every other meta tiles stands for 32x32 pixels. Which is a calculation nightmare if you want, for example, access the level data array based on an absolute x and y position of a character.

That's why the best solution would be a way to remove the last two rows of every name table from view, so that I simply declare one name table worth of data to have 32x28 hardware tiles, ignoring the last two rows completely.

A HUD has nothing to do with it. If my vertical scrolling position is at pixel position 128, then the two last rows of the upper name table are right in the middle of the screen, with or without a HUD.

What I would need, if technically possible, is a way to have the NES display row 27 of name table 0. And then skip row 28 and 29 altogether during rendering and go directly to row 0 of name table 1.
I.e.: When the frame starts, render the screen normally. And as soon as you're at a scanline where tile rows 28 to 29 are currently located, force the vertical scrolling position downward by 16 pixels mid-frame, so that rows 0 to 1 of the next name table are now on the current scanline.

No complicated copying of PPU entries from one place to the other. No extra workaround writes to PPU other than the regular update routines. Just a mid-frame interrupt to skip 16 pixels ahead as soon as the scanline reaches the tile rows that use those crooked attribute values, so that they are never shown, even though they're still there.
But I don't know if that's possible. When I tried it, the IRQ let me change the horizontal scrolling position mid-frame, but it ignored the vertical one.
My game "City Trouble":
Gameplay video: https://youtu.be/Eee0yurkIW4
Download (ROM, manual, artworks): http://www.denny-r-walter.de/city.html
tepples
Posts: 22708
Joined: Sun Sep 19, 2004 11:12 pm
Location: NE Indiana, USA (NTSC)
Contact:

Re: 32x32 pixel meta tiles and vertical scrolling

Post by tepples »

have the NES display row 27 of name table 0. And then skip row 28 and 29 altogether during rendering and go directly to row 0 of name table 1.
On MMC3: Easy. Use an IRQ handler that triggers at the scanline above where you want to make the switch.
On discrete mapper: Not so easy.
User avatar
DRW
Posts: 2225
Joined: Sat Sep 07, 2013 2:59 pm

Re: 32x32 pixel meta tiles and vertical scrolling

Post by DRW »

I tried it out in IRQ, but simply setting the two scrolling values like I do in NMI only worked for horizontal, not vertical. What am I missing?
My game "City Trouble":
Gameplay video: https://youtu.be/Eee0yurkIW4
Download (ROM, manual, artworks): http://www.denny-r-walter.de/city.html
psycopathicteen
Posts: 3140
Joined: Wed May 19, 2010 6:12 pm

Re: 32x32 pixel meta tiles and vertical scrolling

Post by psycopathicteen »

Are you using destructable scenary? If not, you would only need to store 8 bytes in RAM for the attribute tables because you only need to update one row at a time.
Oziphantom
Posts: 1565
Joined: Tue Feb 07, 2017 2:03 am

Re: 32x32 pixel meta tiles and vertical scrolling

Post by Oziphantom »

DRW wrote: Sun Mar 06, 2022 6:55 am
So, either I have to draw the second half of my eighth meta tile to the first rows of the next name table. Which is not a problem for the tiles themselves, but there goes my attribute alignment advantage and I have to store the attributes in RAM again.
You can either have a 16 bytes temp buffer, 8 bytes to hold the current attribute values for fast look up (but I guess slow look up is also possible without the RAM cost), 8 bytes to hold the value read from the PPU, its faster code. But you could just as easily do it with 2 bytes, just you need to
set port ; first address
read value
mask
or
set port ; first address
write value
set port ; second address
write attribute

its slower, but we are only talking 8 times.



While it is a moot point at this point.
With the HUD you never scroll the screen more than 15 pixels, so no you don't have the nametable split in the middle of the screen, you move 15 pixels, shift the screen chars by 2 rows in PPU ram, then set the hardware scroll back to 0. and it will look as if the screen has moved 1 pixels because the tile map has moved by 16 pixels and the y scroll has moved by -15 pixels and hence still 1 pixel.
User avatar
tokumaru
Posts: 12427
Joined: Sat Feb 12, 2005 9:43 pm
Location: Rio de Janeiro - Brazil

Re: 32x32 pixel meta tiles and vertical scrolling

Post by tokumaru »

DRW wrote: Sun Mar 06, 2022 8:56 amI tried it out in IRQ, but simply setting the two scrolling values like I do in NMI only worked for horizontal, not vertical. What am I missing?
The vertical scroll can't be changed mid-screen by normal means. To freely change the scroll mid-screen you need what's known as the $2006/5/5/6 trick. Fortunately for you though, you don't need a complete scroll change, you only need to change the coarse vertical scroll, leaving the horizontal scroll (and fine horizontal and vertical scroll) alone, so you can get away with just a couple of $2006 writes:

1st $2006 write: 0000NNYY
2nd $2006 write: YYYXXXXX
User avatar
DRW
Posts: 2225
Joined: Sat Sep 07, 2013 2:59 pm

Re: 32x32 pixel meta tiles and vertical scrolling

Post by DRW »

Right, I remember. There was that strange method. I'll check it out. Thanks a lot.
My game "City Trouble":
Gameplay video: https://youtu.be/Eee0yurkIW4
Download (ROM, manual, artworks): http://www.denny-r-walter.de/city.html
User avatar
tokumaru
Posts: 12427
Joined: Sat Feb 12, 2005 9:43 pm
Location: Rio de Janeiro - Brazil

Re: 32x32 pixel meta tiles and vertical scrolling

Post by tokumaru »

It's the whole thing about the PPU having a temporary address register (t) and a current address register (v). All $2000, $2005 and $2006 writes affect t, and some or all of t are copied to v after the second $2006 write and at key moments during the frame. You have to know all of this if you plan on freely changing the scroll mid-frame, but in your case you can get away with just the two $2006 writes.

The problem with MMC3 IRQs though is that they fire so late in the scanline that you don't have enough time to do any effects for the scanline that immediately follows.

According to the wiki, MMC3 IRQs fire at PPU cycle 260, and by cycle 320 the PPU is already fetching tiles for the next scanline. That's a very narrow window of 60 PPU cycles, or 20 CPU cycles in NTSC. It's just not enough time for the CPU to call the IRQ handler and then update the scroll. You basically have to wait until the *next* scanline's hblank so you can do the PPU writes.
Post Reply