It is currently Sat Dec 16, 2017 7:38 pm

All times are UTC - 7 hours





Post new topic Reply to topic  [ 51 posts ]  Go to page 1, 2, 3, 4  Next
Author Message
PostPosted: Sun Jan 08, 2017 2:11 pm 
Offline
User avatar

Joined: Sat Sep 07, 2013 2:59 pm
Posts: 1516
I experimented a bit with vertical scrolling and a status bar, but it doesn't seem to work the way I expected it.

At first the standard code for horizontal scrolling with a sprite 0 split:
Code:
; Set scrolling 0 and name table 0
; for the status bar.
LDA #0
STA PpuScroll
STA PpuScroll
LDA #%10010000
STA PpuCtrl

; Wait for sprite 0.
; (Done as a macro.)
WAIT_FOR_PPU_STATUS %01000000

; Set the scrolling position
; and name table for the level.
LDA scrollingPosition
STA PpuScroll
LDA #0
STA PpuScroll
LDA #%10010000
ORA nameTable
STA PpuCtrl

This one works correctly.

Now, I changed the scrolling position code to the following:

Code:
LDA scrollingPosition
STA PpuScroll
LDA #64
STA PpuScroll


Now, I expected the screen below the status bar to be shifted by 64 pixels.
I.e. if the left image is the regular screen, then one with a vertical scrolling of 64 would be the right image:
Attachment:
Example.PNG
Example.PNG [ 8.16 KiB | Viewed 1511 times ]


But the screen still looks like the left image.

It works fine if I set vertical scrolling right away, but when I try to change the scrolling position after the sprite 0 split, i.e. in the middle of the screen, it doesn't work.

Why is that the case? Why can horizontal scrolling be changed in the middle of the screen, but vertical scrolling cannot the way I tried it?

_________________
Available now: My game "City Trouble".
Website: https://megacatstudios.com/products/city-trouble
Trailer: https://youtu.be/IYXpP59qSxA
Gameplay: https://youtu.be/Eee0yurkIW4
German Retro Gamer article: http://i67.tinypic.com/345o108.jpg


Top
 Profile  
 
PostPosted: Sun Jan 08, 2017 2:24 pm 
Offline
User avatar

Joined: Sat Feb 12, 2005 9:43 pm
Posts: 10166
Location: Rio de Janeiro - Brazil
The vertical scroll can't be changed mid-screen through normal means, because of the way the PPU renders the screen. The scroll register, $2005, only affects the temporary VRAM address register, and parts of this register are copied to the actual VRAM address at key moments. At the beginning of the picture, everything is copied, but during rendering, only the X component is copied every scanline, so that the PPU can start each scanline from the left. The Y coordinate is only incremented from the initial value during the whole picture, which is why changing the temporary VRAM address does nothing.

To force a VRAM address update, you have to write to $2006. If you only need to "snap" to whole tiles, which is probably the case with a status bar, 2 $2006 writes will do, but if you need pixel-perfect precision you might need the infamous $2006/5/5/6 trick.

The layout of the bits for the $2006 writes is:

Code:
76543210
*yyyNNYY (first write)
YYYXXXXX (second write)

XXXXX - coarse X scroll
YYYYY - coarse Y scroll
NN - name table
yyy - fine Y scroll

Note that the fine X scroll is stored somewhere else, so you still need a $2005 write if you want to change it.

The need for combining $2006 and $2005 writes for pixel-perfect scrolling arises from the fact that the highest bit of the fine Y scroll is automatically cleared by the PPU on the first write to $2006, so the only way to set it by using a $2006/5/5/6 sequence. Only on the final $2006 write the VRAM address register is changed.

EDIT: This is what the "The skinny on NES scrolling" document is all about. It describes how and when the temporary VRAM register and the actual VRAM register are changed.


Last edited by tokumaru on Sun Jan 08, 2017 2:38 pm, edited 1 time in total.

Top
 Profile  
 
PostPosted: Sun Jan 08, 2017 2:38 pm 
Offline
User avatar

Joined: Sat Sep 07, 2013 2:59 pm
Posts: 1516
Alright, looks like it's not a mundane issue and I need to do some more research.

Which specific technique did "The Legend of Zelda" use when the screen scrolls vertically while the status bar remains in place?

_________________
Available now: My game "City Trouble".
Website: https://megacatstudios.com/products/city-trouble
Trailer: https://youtu.be/IYXpP59qSxA
Gameplay: https://youtu.be/Eee0yurkIW4
German Retro Gamer article: http://i67.tinypic.com/345o108.jpg


Top
 Profile  
 
PostPosted: Sun Jan 08, 2017 3:15 pm 
Offline
User avatar

Joined: Sun Sep 19, 2004 9:28 pm
Posts: 3192
Location: Mountain View, CA, USA
I believe Zelda 1 uses a combination of switching to single-screen mirroring (since it uses MMC1) and some of what tokumaru described above. It doesn't appear to use sprite 0 hit (just in case someone brings that up -- I checked in NO$NES).

http://wiki.nesdev.com/w/index.php/List ... _technique


Last edited by koitsu on Sun Jan 08, 2017 3:16 pm, edited 1 time in total.

Top
 Profile  
 
PostPosted: Sun Jan 08, 2017 3:16 pm 
Offline

Joined: Sun Sep 19, 2004 11:12 pm
Posts: 19353
Location: NE Indiana, USA (NTSC)
From how to split:

  1. .... NN.. Write nametable number << 2 (that is: $00, $04, $08, or $0C) to $2006
  2. YYYY Yyyy Write Y position to $2005
  3. XXXX Xxxx Write X position to $2005
  4. YYYX XXXX Write low byte of nametable address to $2006, which is ((Y & $F8) << 2) | (X >> 3)

Writes 3 and 4 must happen in horizontal blanking between X=256 and X=320.

Given 9-bit X and Y positions (or nametable number and 8-bit X and Y positions), this code fragment by tokumaru calculates the appropriate values to write.


Top
 Profile  
 
PostPosted: Sun Jan 08, 2017 3:29 pm 
Offline
User avatar

Joined: Sat Sep 07, 2013 2:59 pm
Posts: 1516
koitsu wrote:
I believe Zelda 1 uses a combination of switching to single-screen mirroring (since it uses MMC1) and some of what tokumaru described above.

Yeah, I noticed the mirror switching. This one is a good general way to do horizontal and vertical scrolling in the same game, so that you don't have to fiddle around with graphical artifacts. But the mirror switching is still unrelated to the status bar tricks, so yeah, that particular issue is still done with those other methods.

Thanks for your help. I'll have to see whether I do further research for this or whether I simply use a small status bar created from sprites or whether I simply disable rendering during a screen switch.

_________________
Available now: My game "City Trouble".
Website: https://megacatstudios.com/products/city-trouble
Trailer: https://youtu.be/IYXpP59qSxA
Gameplay: https://youtu.be/Eee0yurkIW4
German Retro Gamer article: http://i67.tinypic.com/345o108.jpg


Top
 Profile  
 
PostPosted: Sun Jan 08, 2017 4:56 pm 
Offline
User avatar

Joined: Sat Feb 12, 2005 9:43 pm
Posts: 10166
Location: Rio de Janeiro - Brazil
DRW, there's no need to be scared off by this. Since the status bar is always in the same place, you don't even need to calculate the values to write in real time, you can simply use hardcoded values and that's it.

For example, to set the scroll to (0, 200) in NT 0:

1- write %****00** to $2006 (name table);
2- write %11001000 to $2005 (Y scroll);
3- write %00000000 to $2005 (X scroll);
4- write %00100000 (coarse X scroll, lower 3 bits of coarse Y scroll;

Just do this instead of the $2005+$2005+$2000 writes you currently have, and make sure that writes 3 and 4 happen during hblank, to completely avoid glitches.


Top
 Profile  
 
PostPosted: Sun Jan 08, 2017 8:02 pm 
Offline
User avatar

Joined: Sun Sep 19, 2004 10:59 pm
Posts: 1393
If you're doing vertical scrolling with a status bar, there are basically 3 possibilities:
1. Status bar is at the bottom - you do a 6-6-5 write at the split point (6-6 to set render location, 5 to set fine X scroll)
2. Status bar is at the top, and you have a 4 scanline gap below it - for fine Y scroll of 0-3, you do a 6-6-5 write at the bottom of the gap, and for fine Y scroll of 4-7 you do a 6-6-5 write at the top of the gap.
3. Status bar is at the top, and you have no gap - you do a 6-5-5-6 write at the split point

Most games used technique #1 (SMB3, Startropics) or #2 (Castlevania 3, Battletoads) - technique #3 wasn't really known until we discovered it.

_________________
Quietust, QMT Productions
P.S. If you don't get this note, let me know and I'll write you another.


Top
 Profile  
 
PostPosted: Sun Jan 08, 2017 8:58 pm 
Offline
User avatar

Joined: Fri May 08, 2015 7:17 pm
Posts: 1869
Location: DIGDUG
Forget 'how does zelda do x'. How does Cosmic Epsilon do this? I mean look at this nametable. WTF.


Attachments:
COSMIC.png
COSMIC.png [ 42.41 KiB | Viewed 1400 times ]

_________________
nesdoug.com -- blog/tutorial on programming for the NES
Top
 Profile  
 
PostPosted: Sun Jan 08, 2017 9:03 pm 
Offline
User avatar

Joined: Sat Feb 12, 2005 9:43 pm
Posts: 10166
Location: Rio de Janeiro - Brazil
dougeff wrote:
How does Cosmic Epsilon do this? I mean look at this nametable. WTF.

It has pattern table layouts for different setups of lines coming from the horizon towards the screen, and bankswitches between them several times mid-screen to create vertical detail, and changes the split points over time to create movement. It also changes the horizontal scroll several times when moving the screen sideways, but I'm not sure whether it touches the vertical scroll.

EDIT: Your debugger is configured to display the state of the PPU on scanline 200, which happens to be the last pattern you're seeing on the screen (big cyan stripe on the left, blue on the right), but if you change it to show the state on previous scanlines you'll see each one of the stripe configurations at a time.


Top
 Profile  
 
PostPosted: Mon Jan 09, 2017 1:19 am 
Offline
User avatar

Joined: Fri Nov 12, 2004 2:49 pm
Posts: 7319
Location: Chexbres, VD, Switzerland
Quietust wrote:
If you're doing vertical scrolling with a status bar, there are basically 3 possibilities:
1. Status bar is at the bottom - you do a 6-6-5 write at the split point (6-6 to set render location, 5 to set fine X scroll)
2. Status bar is at the top, and you have a 4 scanline gap below it - for fine Y scroll of 0-3, you do a 6-6-5 write at the bottom of the gap, and for fine Y scroll of 4-7 you do a 6-6-5 write at the top of the gap.
3. Status bar is at the top, and you have no gap - you do a 6-5-5-6 write at the split point

Most games used technique #1 (SMB3, Startropics) or #2 (Castlevania 3, Battletoads) - technique #3 wasn't really known until we discovered it.

Correct, but I'll also mention technique #2b, my favorite, which is the same but uses a 8 scanline gap. You simply do a 6-6-5 write within the gap depending on the fine scroll. Also for both technique 2 and 2b you need to disable background explicitly via $2001 (or via CHR-ROM switch to blank tiles) until the end of the gap.

In addition to that, you can also have one extra pixel of fine scrolling depending on whether the 6-6-5 write is done at the end of the scanline or at the start, so it's possible to have fine-scolling over 5 positions, so it's possible to have only a 3-scanline gap.


Top
 Profile  
 
PostPosted: Mon Jan 09, 2017 2:38 am 
Offline
User avatar

Joined: Sat Feb 12, 2005 9:43 pm
Posts: 10166
Location: Rio de Janeiro - Brazil
Bregalad wrote:
You simply do a 6-6-5 write within the gap depending on the fine scroll. Also for both technique 2 and 2b you need to disable background explicitly via $2001 (or via CHR-ROM switch to blank tiles) until the end of the gap.

Why would you choose to have a mandatory 8 scanline gap, and the added complications of varying the timing and masking the background, while you could just use the 6-5-5-6 sequence instead and have pixel-perfect precision with none of that extra complication?


Top
 Profile  
 
PostPosted: Mon Jan 09, 2017 4:18 am 
Offline
User avatar

Joined: Fri Nov 12, 2004 2:49 pm
Posts: 7319
Location: Chexbres, VD, Switzerland
tokumaru wrote:
Why would you choose to have a mandatory 8 scanline gap, and the added complications of varying the timing and masking the background

Well for most status bars to look good you neede a gap anyway and because the NES is a tiled system a 8-scanline (that is a 1 tile row) gap comes naturally. What you refer to as extra complexity is actually very simple, something like 4 instructions in assembly.


Top
 Profile  
 
PostPosted: Mon Jan 09, 2017 7:21 am 
Offline
User avatar

Joined: Sat Feb 12, 2005 9:43 pm
Posts: 10166
Location: Rio de Janeiro - Brazil
The extra complexity is in timing the actual scroll change, which can happen in any one of 8 scanlines, while with the 6-5-5-6 method you can just split at a constant point, because you have full control over the fine vertical scroll. The 6-6-5 method requires a blank area (which is optional with the other method) more PPU writes, more timed code, and offers no advantage at all.


Top
 Profile  
 
PostPosted: Mon Jan 09, 2017 8:25 am 
Offline
User avatar

Joined: Fri Nov 19, 2004 7:35 pm
Posts: 3969
Do you want pure vertical scrolling only, with no horizontal scrolling at all?
If so, you can use the nametable arrangement found in Super Mario 3's vertical scrolling stages:
Attachment:
mario3_vertical.png
mario3_vertical.png [ 1.28 KiB | Viewed 1300 times ]


It's vertical mirroring, but with the second nametable used exclusively for the status bar. There are no scrolling glitches on the left nametable since the status bar hides them.

Some other games use single screen mirroring and switch the nametable when switching to the status bar. Still other games simulate single screen mirroring with IRQ and scrolling tricks.

_________________
Here come the fortune cookies! Here come the fortune cookies! They're wearing paper hats!


Top
 Profile  
 
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 51 posts ]  Go to page 1, 2, 3, 4  Next

All times are UTC - 7 hours


Who is online

Users browsing this forum: Google Adsense [Bot], Yahoo [Bot] and 6 guests


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Jump to:  
Powered by phpBB® Forum Software © phpBB Group