This page is a mirror of Tepples' nesdev forum mirror (URL TBD).
Last updated on Oct-18-2019 Download

Seamless All-direction Scrolling

Seamless All-direction Scrolling
by on (#202339)
So, I thought we had talked about this before, and it seemed easy, but I'm scratching my head. All direction scrolling, without showing tiles change, nor attribute table errors...

I was thinking vertical mirroring, would make it easy to scroll left and right without problem. And, leaving BG rendering off for the top 16 pixels would solve up/down scrolling issues. It might be very hard to time this correctly...(NROM) since sprite zero hit won't work with BG off.

Any other suggestions?

Horizontal mirroring with sprites hiding the right and pixels turned off on the left?
Re: Seamless All-direction Scrolling
by on (#202343)
For a long time I did exactly what you described, but instead of the sprite 0 hit I used a sprite overflow to time the blanking at the top of the screen. Conveniently enough, the 9 sprites also masked any sprites that happened to go up there. The down side is that, besides losing 9 sprites, you have to waste 8 or 16 scanlines worth of CPU time, depending on the height of your sprites.

To avoid headaches once and for all, I finally switched to a 4-screen layout (i.e. no mirroring). If the cartridge uses CHR-RAM, 4-screen comes for free because of the RAM sizes available today.
Re: Seamless All-direction Scrolling
by on (#202348)
Sprite Overflow.

4-screen VRAM.

Both good suggestions. Thank you. That's what I was looking for.
Re: Seamless All-direction Scrolling
by on (#202367)
What mapper do you suggest to use with 4-screen?

Looks like standard MMC3 can do 4-screen and it seems like a good mapper to me. CHR-RAM, PRG-RAM, nametable arrangement control (or 4-screen), scanline IRQ and a good amount of PRG and CHR space.
Re: Seamless All-direction Scrolling
by on (#202368)
Quote:
What mapper do you suggest to use with 4-screen?

If you can live without scanline irqs, GTROM is great. Powerful for its home tinkerer friendly price per board.
Re: Seamless All-direction Scrolling
by on (#202376)
Any mapper can do 4-screen, but some mappers may require more complicated logic on the cartridge than others. On discrete logic mappers with CHR-RAM, the use of 4-screen is trivial: one wire on the cartridge tells the NES to keep its internal VRAM permanently off so the VRAM in the cartridge (which must be at least 16KB) is used not only for attribute tables, but also for name tables.

GTROM is cool and takes things a step further, doubling the CHR-RAM and NT capacity through bankswitching.
Re: Seamless All-direction Scrolling
by on (#202381)
I see. That's good as long as the 4-screen modifications doesn't conflict with any behaviour defined in iNES or NES 2.0 standard, so that it doesn't work properly in emulators or flashcarts.

While GTROM is interesting it seems it only comes in 72-pin. I have no NES and I'd avoid using an adapter if possible.


To get back on topic, if 4-screen can't be used for whatever reason, what other options are there besides sprite overflow?
Re: Seamless All-direction Scrolling
by on (#202382)
Some of its features are probably not implemented in emulation. 7.5kB extra ram accessible via PPU address space, self modification (since it's flash), the two LEDs come to mind. I assume the LEDs were included as an easy way to say "don't shut me off while i'm saving your precious game/modifying myself!"
Re: Seamless All-direction Scrolling
by on (#202387)
Many years ago, someone (tepples?) observed that "XOR" nametable layout (▞) should make almost-seamless scrolling possible ...

We're pretty certain that no commercial games used it—preventing glitches just wasn't a high enough priority—but the hardware needed is trivial, and any mapper with the ability to arbitrarily configure nametables could be used to develop for it.
Re: Seamless All-direction Scrolling
by on (#202390)
I find it interesting to observe that besides Tengen's Gauntlet and Irem's Napoleon Senki (and Rad Racer 2, which doesn't seem to use it for actual four-way scrolling), the only other games that use 4-screen VRAM (and that I'm aware of) are Sachen games, namely Jurassic Boy 2, Rocman X and Zhōngguó Dàhēng. Zhōngguó Dàhēng actually uses six nametables --- four on cartridge RAM for the game board, and the two in the console for the status bar.
Re: Seamless All-direction Scrolling
by on (#202394)
NewRisingSun wrote:
I find it interesting to observe that besides Tengen's Gauntlet and Irem's Napoleon Senki (and Rad Racer 2, which doesn't seem to use it for actual four-way scrolling), the only other games that use 4-screen VRAM (and that I'm aware of) are Sachen games, namely Jurassic Boy 2, Rocman X and Zhōngguó Dàhēng. Zhōngguó Dàhēng actually uses six nametables --- four on cartridge RAM for the game board, and the two in the console for the status bar.

Well, right now it's no cheaper to get 8k than 64k SRAM, hence why it's basically a "for free" feature if you have CHR-RAM. Those Sachen games you mentioned all came well after the official commercial era of NES games had ended. I don't know what RAM costs were like in the late 90s but there's probably a point in there where it was just really cost effective to have extra nametable RAM + CHR-RAM.
Re: Seamless All-direction Scrolling
by on (#202396)
FrankenGraphics wrote:
Some of its features are probably not implemented in emulation. 7.5kB extra ram accessible via PPU address space, self modification (since it's flash), the two LEDs come to mind. I assume the LEDs were included as an easy way to say "don't shut me off while i'm saving your precious game/modifying myself!"

I implemented if in FCEUX about a year ago. Aside from the LEDs, I think it's actually a "complete" implementation. It even does the flashing.

The "extra ram via PPU" thing isn't its own special feature, it's just a side effect of the nametable banking. $3000-3F00 isn't used by rendering, but the SRAM is just mapped flatly across it anyway in case you want to use it.

(It was just after the last stable release of FCEUX, unfortunately, but there's an interim build available on the site that would have it.)
Re: Seamless All-direction Scrolling
by on (#202400)
rainwarrior wrote:
Well, right now it's no cheaper to get 8k than 64k SRAM, hence why it's basically a "for free" feature if you have CHR-RAM.

Unless you're already banking the CHR RAM to allow more than 4K for background tiles and 1K for player and boss sprite cels without slowing down background tile animations. Haunted: Halloween '85 uses the same board as Lizard, which provides 8K CHR RAM to allow 256 background tiles at once and double-buffered 256-byte sprite cels that take two frames to load. Its sequel The Curse of Possum Hollow, by contrast, uses separate 4K CHR RAM banks for the playfield, the parallax strips, and the subtitle font, and sprite cels are arranged into 1K sheets each loaded over the course of eight frames. Most of this CHR trickery could have been done with the TQROM setup, but an 8K RAM and 64K ROM is probably more expensive.

It's tricky to use video memory at $3000-$3EFF for game logic because you have to wait for vblank, which may already be chock full of tile and nametable transfers to video memory, and you have to know a frame in advance what memory you're going to need to read.
Re: Seamless All-direction Scrolling
by on (#202405)
Pokun wrote:
What mapper do you suggest to use with 4-screen?

To be honnest the most elegant mapper which does it is Napoleon Senki's mapper. It does it in a very elegant way using 2kb of CHR-ROM for animated tiles, and using the remaining 6kb for CHR-RAM and leaving 2 extra KB for 2 name tables, combined with the CIRAM for the other 2. It's amazing. Unfortunately this mapper was wasted on a horrible game.

As for your original post:
Quote:
So, I thought we had talked about this before, and it seemed easy, but I'm scratching my head. All direction scrolling, without showing tiles change, nor attribute table errors...

Outside of 4-screen mirroring which I consider a bit cheating, there is only one way to go really for FULLY clean scrolling with no attribute clash, and no sprite popping : Use vertical mirroring with 16 scanlines at the top hidden AND use $2001 to hid the left 8 pixels. If you use 8x8 sprites, you can hide the top and bottom 8 scanlines instead of the top 16, but it'd be hard to achieve without an IRQs mapper. Hiding the top 16 lines however is very much doable without an IRQ mapper. It requires a constant-timed NMI routine but I don't think it's even close to impossible to achieve :)

PS: Technically you could do it with "only" 15 hidden lines, 16 aren't needed, but you get the idea.
Re: Seamless All-direction Scrolling
by on (#202406)
Bregalad wrote:
Hiding the top 16 lines however is very much doable without an IRQ mapper. It requires a constant-timed NMI routine

It doesn't require a constant-timed NMI routine. If you can guarantee a sprite 0 hit or a sprite overflow (which is what I use to mask sprites at the top of the screen as opposed to keeping rendering completely off and getting the alternate dot crawl pattern) every frame, you can wait for one of these flags to be cleared in order to detect the end of vblank after you're done with your non-contant-timed NMI handler. Then you wait 16 scanlines with timed code (you can do some contant-timed tasks here if you want), and finally turn background rendering on.
Re: Seamless All-direction Scrolling
by on (#202462)
Ok, I got a 99% funcional all-direction (top down) engine working. (99% because I see some missing tiles in the corners if you're going diagonally).

No attribute tables yet. No collisions with BG yet. Had to rewrite how neslib handles scrolling, and rewrite the nmi routine.

I'm going to have to drop this project and get back to it...I have so many things to work on right now.

Edit, I'm using 4 screen mode, btw.
Re: Seamless All-direction Scrolling
by on (#202467)
tokumaru wrote:
It doesn't require a constant-timed NMI routine. If you can guarantee a sprite 0 hit or a sprite overflow (which is what I use to mask sprites at the top of the screen as opposed to keeping rendering completely off and getting the alternate dot crawl pattern) every frame, you can wait for one of these flags to be cleared in order to detect the end of vblank after you're done with your non-contant-timed NMI handler. Then you wait 16 scanlines with timed code (you can do some contant-timed tasks here if you want), and finally turn background rendering on.

You are indeed right that a constant-timed NMI routine is not needed. For some reason I tought sprite zero hit was mainly for synchronizing at the HIT point, but I forgot that it also allows to synchronize at the end of VBlank, even if the hit point is not even used at all !

Techniques for blanking the first 8 or 16 lines (needed if you do not want any sprite pop-up !) can range from disabling BG by $2001 and having 8 high priority sprites there, to disable rendering completely, or leave everything enabled but use blank CHR-ROM pages for everything.

Also I forgot to mention that IF you're using 8x8 sprites, you could also use horizontal mirroring, and hide the left and right 8 pxiels (requires 30 sprites !!) and hide only the top 8 lines. Since it requires so many sprites, it's not the greatest idea, but it's an alternate way to get completely glitch-free scrolling without sprite poping nor attribute clases. I still belive vertical mirroring to be more convenient.

Quote:
Edit, I'm using 4 screen mode, btw.

Booo cheating !
Just kidding, actually hardware wise it makes a lot of sense to solve the problem this way, but it isn't the 80's way of solving the problem.
Re: Seamless All-direction Scrolling
by on (#202473)
I don't understand how you can mask the topmost 8 or 16 scanlines of BG characters using just 8 high priority sprites? Sprites are just 8 dot wide and BG characters are not affected by the sprite overflow.
Re: Seamless All-direction Scrolling
by on (#202474)
dougeff wrote:
(99% because I see some missing tiles in the corners if you're going diagonally).

This usually happens because of rows overwriting columns and/or vice versa. When you move diagonally, the column and the row that need to be updated overlap at the corner of the screen, so if you do things in the wrong order, you may corrupt that corner.

Quote:
No attribute tables yet.

I guess you were a bit too optimistic with that 99% figure then... attributes are easily the worst part of an 8-way scroller, specially if the map is built with 256x256-pixel blocks instead of 256x240 ones. I think you mentioned using 256x240, so your case is not so bad, but you still have to split and combine attribute bytes vertically when updating rows, which's kind of annoying.

Quote:
Edit, I'm using 4 screen mode, btw.

Oh, so you may not need to do any serious attribute juggling after all.

Bregalad wrote:
Techniques for blanking the first 8 or 16 lines (needed if you do not want any sprite pop-up !) can range from disabling BG by $2001 and having 8 high priority sprites there, to disable rendering completely, or leave everything enabled but use blank CHR-ROM pages for everything.

Yeah, that's right. Jurassic Park uses the blank (actually black) patterns approach. This is better because it doesn't waste any sprites, but the other method is not so bad IMO.

Quote:
Also I forgot to mention that IF you're using 8x8 sprites, you could also use horizontal mirroring, and hide the left and right 8 pxiels (requires 30 sprites !!) and hide only the top 8 lines. Since it requires so many sprites, it's not the greatest idea, but it's an alternate way to get completely glitch-free scrolling without sprite poping nor attribute clases. I still belive vertical mirroring to be more convenient.

Felix the Cat and Alfred Chicken use sprites to hide the rightmost column of the background, but I'm pretty sure they use 8x16 sprites. That's still pretty wasteful though, because not only you have to waste 15 sprites (compared to only 9 with the other approach), but you also effectively reduce the number of sprites per scanline to 7, as if 8 wasn't already bad enough.

Quote:
hardware wise it makes a lot of sense to solve the problem this way

That was my conclusion. No need to be masochistic about something just so you can be 100% authentic to some specific time period, if you can just go with a very simple solution that has no real drawbacks.
Re: Seamless All-direction Scrolling
by on (#202475)
Pokun wrote:
I don't understand how you can mask the topmost 8 or 16 scanlines of BG characters using just 8 high priority sprites? Sprites are just 8 dot wide and BG characters are not affected by the sprite overflow.

The high priority sprites are for hiding sprites only (and you need 9 if you want to trigger the overflow flag)... the background is disabled normally using $2001, which's why you need timed code to enable the it back at the correct time.
Re: Seamless All-direction Scrolling
by on (#202477)
Oh now I see. I misunderstood Bergalad's message, he said turn off BG AND hide sprites using sprite overflow.

OK so by only turning off the BG it doesn't count as forced blanking because sprites are still on, just that stray sprites that go up there are hidden by the overflow.
Re: Seamless All-direction Scrolling
by on (#202482)
Exactly. There are two advantages in using a sprite overflow instead of disabling rendering completely:

1- By keeping rendering on, you avoid the alternate dot crawl pattern in NTSC, which can look weird;

2- You can use the sprite overflow flag to sync up with the start of the frame, eliminating the need for a constant-timed NMI handler, which is all but trivial to code.
Re: Seamless All-direction Scrolling
by on (#202501)
3- You finally get to use that buggy sprite overflow flag, although probably not what it was designed for!

BTW how exactly do you check for the flag? Do you poll $2002 in the beginning of your main loop right after a vblank or something?
Re: Seamless All-direction Scrolling
by on (#202512)
If you want to detect the end of vblank, you have to poll $2002 in the vblank handler, after all PPU operations are done, waiting for the overflow flag to be *cleared*.

All raster effects timed from the start of the frame should be done in the NMI handler, because you want them to happen every frame, even if the game logic lags, otherwise the image will glitch every time the game slows down.
Re: Seamless All-direction Scrolling
by on (#202533)
And, more importantly:

4 - You can scroll using $2005/$2000 normally and don't have to touch $2006.

On the other hand, an advantage of using real forced blanking for the first 16 lines would be to have extended time for VRAM updates.

Using sprite overflow flag might be elegant, but does it really work ? I mean all I heard about this flag is that it's buggy and it's usage should be avoided.
Re: Seamless All-direction Scrolling
by on (#202536)
Yeah I thought that as well, how can you rely on it if it's inconsistent? But according to the wiki: "games can intentionally place 9 or more sprites in a scanline to trigger the overflow flag consistently, as long as no previous scanlines have exactly 8 sprites." It sounds like its behaviour is consistent on the very first overflow. And if you use it on the first 8 scanlines there should be no risk for unexpected behaviour.


tokumaru wrote:
If you want to detect the end of vblank, you have to poll $2002 in the vblank handler, after all PPU operations are done, waiting for the overflow flag to be *cleared*.

All raster effects timed from the start of the frame should be done in the NMI handler, because you want them to happen every frame, even if the game logic lags, otherwise the image will glitch every time the game slows down.

I see, one disadvantage of this is that you are potentially loosing some time for your logic to run in waiting for the flag I guess. But slowdown is better than graphical glitches.
Re: Seamless All-direction Scrolling
by on (#202544)
Yeah, sprite overflow is buggy, but 9 high priority sprites before anything else does guarantee that the flag is set consistently.

Pokun wrote:
I see, one disadvantage of this is that you are potentially loosing some time for your logic to run in waiting for the flag I guess. But slowdown is better than graphical glitches.

Yeah, you waste some time waiting for the end of vblank, and some more while timing the border itself, but you may at least run constant-timed tasks during the second wait... Maybe a constant-cycle music engine?
Re: Seamless All-direction Scrolling
by on (#202595)
Here's a video of my top-down, all direction game engine (like Crystalis). Will put on the blog soon. Got collisions and attribute tables working. Coding this was a huge pain in the ass (or back, since it's actually my back and eyes that hurt)...about a dozen bugs that I fixed, probably more that I missed.

https://youtu.be/gqVa3RHxMjE


All the 'under the hood' code is in asm, but the main code is in C (cc65). I am buffering nametable writes every frame, lots of them. 130 scanlines of filling buffers, and there's no music.

EDIT - and right up against the end of v-blank every frame, like 10-20 instructions before the pre-render scanline. So...basically, no PPU updates or palette changes of any kind, unless I shut off my own PPU updates for a frame.
Re: Seamless All-direction Scrolling
by on (#202602)
dougeff wrote:
130 scanlines of filling buffers, and there's no music.

Quote:
and right up against the end of v-blank every frame, like 10-20 instructions before the pre-render scanline.

Those could be serious problems for a fast-paced game, but might be OK for something slower, like an RPG.
Re: Seamless All-direction Scrolling
by on (#202641)
This is great, but why not first make a single left-right scrolling, and another simple scroll up-down?

The scroll advantage 4 nametables is very interesting, but I think before reaching this easier to explain first serious lesson right?
Re: Seamless All-direction Scrolling
by on (#202673)
[Re, 1 direction scrolling]

Maybe next time. I'm very busy these days.

Also, you can use the all-direction engine to just go horizontally (keep Y at zero, or in the 2 nametable tall range)...or vertically (keep X zero, ot in the 2 nametable wide range)...with slight modification.

And stop calling the "fill the ppu buffer" for the opposite direction, and change the mirroring in the .cfg file, if you want.
Re: Seamless All-direction Scrolling
by on (#202675)
Yes, I was testing things yesterday.

I managed to run from left to right and from right to left by setting the mirror to horizontal in.cgf, and in lesson28.h the MAX_SCROLLING_Y to 0. This enabled the screen to lock up and down.

However, when I move, there comes a moment on the screen number 4-5 that begin to appear glicht graphics and gives problems.
In addition, it really seems that the nametables are loaded two by two vertically, and although BGTABLE only left, for example, 9 nametables, these were loaded from top to bottom.

I do not know if I understand the last one I've written. I am sorry
Re: Seamless All-direction Scrolling
by on (#202680)
Hmm, maybe there's some bugs in the code.

I will look at it ...some day.


EDIT - I didn't have any problems, when I changed #define ROOMS_HIGH 1
(essentially the same as MAX_SCROLL_Y 0)

I didn't change the .cfg mirroring. I don't think that should be the problem either. Or, maybe that is the problem...yes...it does load 2 rooms tall worth of tiles when you scroll left and right... You would need to go to DrawBG.s and in _CSV2NT_COL_FILL: at line 280 it should just do...

lda #$ff
sta _Col_Buffer+62
jmp Col_Ready

to skip the second half of the 'Draw a column' function.

And, shouldn't it be vertical mirroring? To do horizontal scrolling? It's too early in the morning, I need some coffee.


EDIT 2 - still see some graphic errors. Looks like there is bugs in the code.


EDIT 3 - I think the problem then, is the CSV2NT_ROW_FILL function is being called, and it shouldn't be. I commented out refereces in lesson28.c on lines 292 and 301, and edited CSV2NT_FULL to do 1 fewer row. Seems to work.
Re: Seamless All-direction Scrolling
by on (#202691)
dougeff wrote:
Hmm, maybe there's some bugs in the code.

I will look at it ...some day.


EDIT - I didn't have any problems, when I changed #define ROOMS_HIGH 1
(essentially the same as MAX_SCROLL_Y 0)

I didn't change the .cfg mirroring. I don't think that should be the problem either. Or, maybe that is the problem...yes...it does load 2 rooms tall worth of tiles when you scroll left and right... You would need to go to DrawBG.s and in _CSV2NT_COL_FILL: at line 280 it should just do...

lda #$ff
sta _Col_Buffer+62
jmp Col_Ready

to skip the second half of the 'Draw a column' function.

And, shouldn't it be vertical mirroring? To do horizontal scrolling? It's too early in the morning, I need some coffee.


EDIT 2 - still see some graphic errors. Looks like there is bugs in the code.


EDIT 3 - I think the problem then, is the CSV2NT_ROW_FILL function is being called, and it shouldn't be. I commented out refereces in lesson28.c on lines 292 and 301, and edited CSV2NT_FULL to do 1 fewer row. Seems to work.


Mmm, a little hard

My config:

lesson28.h
#define ROOMS_HIGH 1
#define MAX_SCROLL_Y 0

.cgf
NES_MIRRORING: type = weak, value = 1;

lesson28.c
Commented lines and remains so, but this is not whether it is right, because then nothing moves.
Code:
/*
      if (direction == GoRight){
         tempX = masterX + 0x100;
         tempY = masterY;
         CSV2NT_COL_FILL();
      }
      else {
         tempX = masterX - 0x10;
         tempY = masterY;
         CSV2NT_COL_FILL();
      }
*/


DrawBG.s
Add these lines at position 280
Code:
   ;62
   ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
   ;next column, nametable down one
   inc _tempY+1
   lda #$ff
   sta _Col_Buffer+62
   jmp Col_Ready


This still does not work correctly what is supposed to be corrected in CSV2NT_FULL?

EDIT:
In addition, change the BGtable to make a single row and I think that is where there really a problem. As they have nothing to load down errors occur.

Code:
const unsigned char * const BG_TABLE[] = {
BG00, BG01, BG02, BG03, BG04, BG05, BG06, BG07
};


EDIT 2:
It seems that there is a limit when creating METATILES for BACKGROUND

How can increase?
Re: Seamless All-direction Scrolling
by on (#203715)
I've been testing your scroll engine and good. . . can be reached has to make a Star Wars - The Return of the Jedi who never left hahaha :D

Image Image
Re: Seamless All-direction Scrolling
by on (#203730)
I'm glad someone can make sense of my code. I've been too busy to write a proper blog page. Or comment the code.

I'm definitely going to change the code, ...and make a H scroll only and a V scroll only version of the same.
Re: Seamless All-direction Scrolling
by on (#203734)
Great!
Re: Seamless All-direction Scrolling
by on (#204259)
I regret to report that the engine 4 nametable scroll does not work properly in PAL NES version.

https://www.youtube.com/watch?v=Qc0p-Gv7LzI
Re: Seamless All-direction Scrolling
by on (#204268)
Ok.

I'm assuming you are testing on a cartridge that can do 4 screen mirroring?
Re: Seamless All-direction Scrolling
by on (#204282)
dougeff wrote:
Ok.

I'm assuming you are testing on a cartridge that can do 4 screen mirroring?


No. I'm testing on a flashcard but now that you mention it will test a PCB compatible with 4 nametable and I said something. :roll:
Re: Seamless All-direction Scrolling
by on (#204283)
FYI, I spotted some attribute problems (miscolored tiles) when trying that Star Wars demo.
Re: Seamless All-direction Scrolling
by on (#204286)
Ok, I just made several attempts on different plates. A PCB Second Dimension is and the other is Retro-Stage.

Image

Image

Previously, I tried an ordinary rom to verify that both plates were functioning properly. In this case, I used the Super Mario Bros. rom and everything went well.

Then I tried SW-RotJ rom. I soldered V and H. In both cases the effects were the same. Can these plates are incompatible with 4 screen?

https://www.youtube.com/watch?v=Zj8wDVlfi3Y


As you can see, the result is different. Besides making a wrong scroll, blink several metatiles across the screen.
Re: Seamless All-direction Scrolling
by on (#204288)
None of these boards support 4-screen name table layout. If you're soldering H and V tabs, that means you're using mirroring, and 4-screen is precisely the lack of mirroring.
Re: Seamless All-direction Scrolling
by on (#204289)
tokumaru wrote:
None of these boards support 4-screen name table layout. If you're soldering H and V tabs, that means you're using mirroring, and 4-screen is precisely the lack of mirroring.


Indeed, you're right. Even unsoldering H and V still did not work, therefore, these plates are not compatible with screen 4 mirror.

However, I tested with GTROM / Cheapocabras and if it works smoothly:

https://www.youtube.com/watch?v=MgiqSY10zzA