User:Bregalad/Scrolling sandbox: Difference between revisions
(Separate regular scrolling and split scrolling) |
m (Oops.) |
||
(3 intermediate revisions by the same user not shown) | |||
Line 1: | Line 1: | ||
This is my proposal for a new [[scrolling]] page. | This is my proposal for a new [[scrolling]] page. Some information which is currently on the [[mirroring]] page should be moved here. On the other hand, complex scrolling techniques are moved to a new [[scroll split]] page. Feedback and constructive critisism is welcome. | ||
Sections ''Unidirectional scrolling'' and ''Mirroring chart'' were just moved arround, other sections were significantly altered by myself (Bregalad). | |||
''' !! CURRENTLY THIS PAGE IS A WORK IN PROGRESS !!''' | ''' !! CURRENTLY THIS PAGE IS A WORK IN PROGRESS !!''' | ||
'''Scrolling''' is the movement of the displayed portion of the map. Games scroll to show an area larger than the 256x240 pixel screen. For example, areas in ''Super Mario Bros.'' may be up to 24 screens wide. The NES's first major improvement over its immediate predecessors (ColecoVision and Sega Mark 1) was pixel-level scrolling of playfields. | |||
== Unidirectional scrolling == | |||
Ordinarily, a program writes to two [[PPU registers]] to set the scroll position in its NMI handler: | |||
#Find the X and Y coordinates of the upper left corner of the visible area (the part seen by the "camera") | |||
#Write the X coordinate to [[PPUSCROLL]] ($2005) | |||
#Write the Y coordinate to PPUSCROLL | |||
#Write the starting page (high order bit of X and Y) to bits 0 and 1 of [[PPUCTRL]] ($2000) | |||
The scroll position written to PPUSCROLL is applied at the end of vertical blanking, just before rendering begins, therefore these writes need to occur before the end of vblank. Also, because writes to [[PPUADDR]] ($2006) can overwrite the scroll position, the two writes to PPUSCROLL must be done after any updates to VRAM using PPUADDR. | |||
L- or X-shaped [[mirroring]] | By itself, this allows moving the camera within a usually two-screen area (see [[Mirroring]]), with horizontal and vertical wraparound if the camera goes out of bounds. | ||
To scroll over a larger area than the two screens that are already in VRAM, new tile and attribute data decompressed from leve data has to be filled in the nametables, as seen in the animation below. | |||
The area that needs rewritten at any given time is sometimes called the "seam" of the scroll. | |||
[[File:SMB1 scrolling seam.gif|center]] | |||
=== Frequent pitfalls === | |||
; Taking too long: If a NMI handler routine takes too long and PPUSCROLL ($2005) is not set before the end of vblank, the scroll will not be correctly applied the following frame. Most games do not write more than 64 bytes to VRAM per NMI, more than this may require on NTSC consoles advanced loop unrolling techniques to fit the narrow window of time offered by the VBlank period. | |||
; Set the scroll last: PPUSCROLL ($2005) must always be set after using PPUADDR ($2006). They have a shared internal register and using PPUADDR ($2006) will overwrite the scroll position. | |||
=== PPU registers === | |||
When split scrolling is required, some more advanced usage of $2005 and $2006 registers is needed. The complete information is is on a separate page : [[split scrolling]]. | |||
== Multi-directional scrolling techniques == | |||
Scrolling in a direction in which the screen is not mirrored is usually easy, since there is a whole screen of buffer space to update data. On the other hand, dealing with scrolling updates is harder when the axis in the direction it is scrolled to is [[mirrored|mirroring]], because graphics leaving one side of the screen directly enters the other side. | |||
The rarely-available L- or X-shaped [[mirroring]] could facilitate changes in scrolling direction on screen-boundaries without having to flip between Horizontal and Vertical mirroring. | |||
=== Horiontal scrolling with horizontal [[mirroring]] === | |||
Doing any horizontal scrolling using horizontal mirroring is hard to do smoothly because the data on the right of the screen is immediately show on the left due to mirroring. Clever use of hardware left-side screen clipping will hide all name table glitches, but because the attribute tables have a resolution of 2x2 tiles, there will always be attribute glitches on the left and/or the right side of the screen. Some televisions overscan up to 8 pixels on both left and right border, but most doesn't. PAL NESes will automatically clip the left and right 2 pixels. Several solutions exists: | |||
* Ignore the problem: Colour glitches are accepted, and are minimized (see below) | |||
* Work arround the problem: Levels use only a single palette (as implemented by ''Wizard & Warriors II''), or have a level design where the colour scheme repeats itself vertically each screen. This seriously reduces the graphical possibilities. | |||
* Fix the problem: Overlay 8 additional pixels of BG with sprites. This can be either solid-colour sprites designed to hide bachground graphics (as in the game ''Alfred Chicken''), or sprites reusing BG graphics and correct colours instead of the incorrect colour from the attribute table. Very few games do this because it reduces the number of (actual) sprites per scanline to 7 and wastes a lot of OAM space (roughly 1/4 in 8x16 pixel sprite mode). | |||
If glitches are accepted they appear to at least 7 pixels due to techincal reasons (assuming left-clip is enabled via $2001). Several strategies exist however to make them less blatant: | |||
* Make the various BG palettes use the same luminosity pattern and only changing the hues, that way the area will be wrong colored will at least have correct luminosity, and as such, look less wrong. | |||
* Make the glitches in the direction the player is not facing (as seen in ''Kirby's Adventure''). | |||
* Share the glitches on both borders, so the total area of graphics showing with the wrong colour will be minimized. For example 4 pixels on the right side and 3 pixels on the left side. On PAL consoles, this will reduce to 2 and 3 respectively. | |||
Games with such glitches typically does a poor job at minimizing the amount of glitches, so they give a bad impression as to what is actually possible. | |||
This diagram shows how the glitches can be minimized for a 16-pixel horizontal scroll cycle, each line representing a different fine horizontal scroll value. | |||
<nowiki>Fine | |||
HScroll | |||
0 --------|------------------------ | |||
1 #-------|------------------------ | |||
2 ##------|------------------------ | |||
3 ###-----|------------------------ | |||
4 ####----|------------------------ | |||
5 #####---|------------------------ | |||
6 ######--|------------------------ | |||
7 #######-|------------------------ | |||
8 ~~~~~~~~|------------------------ (NT update) | |||
9 #~~~~~~~|~----------------------- | |||
10 ##~~~~~~|~~---------------------- | |||
11 ###~~~~~|~~~--------------------- | |||
12 xxxx----|--------------------~~~~ (AT update) | |||
13 xxxxx---|---------------------~~~ | |||
14 xxxxxx--|----------------------~~ | |||
15 xxxxxxx-|-----------------------~ | |||
0 --------|------------------------ (NT update) | |||
^^^^^^^^ ^^--- Hidden on PAL machines | |||
Hidden part (by hardware through $2001) | |||
- Correct tile displayed with correct colorus | |||
~ Correct tile displayed with wrong colours | |||
x Wrong tile displayed with correct colours | |||
# Wrong tile displayed with wrong colours</nowiki> | |||
=== Vertical scrolling with vertical [[mirroring]] === | |||
Because data that is on the top/bottom of the screen will immediately show up on the other side, a clever use of NTSC [[overscan]] can make it glitch-less multidirectional scrolling, but glitches will appear on PAL televisions (and NTSC televisions with a overscan range which is a little off). Because the vast majority of commercial games were developped in NTSC countries, they tend to consider the vertical overscan as a safe buffer zone for scroll updates. | |||
However, as with the case of horizontal scrolling with horizontal mirroring, it is desirable to minimize the unavoidable glitches. The best possible way to hide glitches is to make 4 pixels with wrong tiles and 4 additional pixels with wrong color on both sides. Games with such glitches typically does a poor job at minimizing the amount of glitches, so they give a bad impression as to what is actually possible. | |||
Perfectionist programmers could use raster split to hide glitches, and possibly also provide more blanking time to update VRAM as well as hiding the unavoidable sprite poping in the top border. This is seen in the games ''Jurassic Park'' and ''M.C. Kids'', but it was rarely done because it complicates the code a lot for little benefits. | |||
This diagram shows how the glitches can be minimized for a 16-pixel vertical scroll cycle, each column representing a different fine vertical scroll value. | |||
<nowiki>Fine | |||
VScroll 0123456789ABCDEF0 | |||
-###~~~~-xxx----- < Hidden by | |||
--##~~~~--xx----- < NTSC average | |||
---#~~~~---x----- < Overscan | |||
----~~~~--------- < | |||
-----~~~--------- < | |||
------~~--------- < | |||
-------~--------- < | |||
----------------- | |||
----------------- | |||
----------------- | |||
----------------- | |||
----------------- | |||
----------------- | |||
----------------- | |||
----------------- | |||
----------------- < | |||
--------~-------- < | |||
--------~~------- < | |||
--------~~~------ < | |||
----x---~~~~#---- < | |||
----xx--~~~~##--- < Hidden by | |||
----xxx-~~~~###-- < NTSC average | |||
----xxxx~~~~####- < Overscan | |||
^(NT update) | |||
^(AT update) | |||
^(NT update) | |||
- Correct tile displayed with correct colorus | |||
~ Correct tile displayed with wrong colours | |||
x Wrong tile displayed with correct colours | |||
# Wrong tile displayed with wrong colours</nowiki> | |||
=== Status bars and single-screen mirroring === | |||
Single-screen [[mirroring]]'s main advantage is that it allows using a status bar at the top or bottom of the screen while also allowing the playfield to extend equally in any direction. Typically the status bar is stored in one nametable and the playfield in the other. Scrolling parameters and nametables are switched the appropriate screen location during rendering. | |||
Due to the screen layout being entierely linearly adressable, the calculation of PPU addresses of name and attribute tables updates are significantly simpler, leading to typically faster, more efficient scrolling routines. A variable sized or self-scrolling status bar can relatively easily be created thanks to 1-screen mirroring. | |||
The same graphical glitches as discussed above under horizontal mirroring will happen. However, as long as there is a status bar, glitches are fully avoidable vertically since the data that falls off the bottom (or the top) of the screen will come in the area that is "hidden" by the status bar, regardless of overscan factors. | |||
== Mirroring chart == | == Mirroring chart == | ||
This table lists the | This table lists the most common mirroring and scrolling techniques. There are a huge variety of more complicated techniques. For a more comprehensive survey, see: [[List of games by mirroring technique]] | ||
{| class="wikitable" | {| class="wikitable" | ||
Line 38: | Line 152: | ||
| Horizontal | | Horizontal | ||
| ''Ice Climber'', ''Gun.Smoke'' | | ''Ice Climber'', ''Gun.Smoke'' | ||
| Without a status bar, horizontal mirroring is the best choice for vertical-only scrolling. With a status bar, vertical or single-screen mirroring | | Without a status bar, horizontal mirroring is the best choice for vertical-only scrolling. With a status bar, vertical or single-screen mirroring gives a place in the nametable to render the status bar, and the scrolling seam should be hidden under the bar. | ||
|- | |- | ||
| Alternating Horizontal/Vertical | | Alternating Horizontal/Vertical | ||
Line 48: | Line 162: | ||
| Horizontal/Vertical | | Horizontal/Vertical | ||
| ''Super Mario Bros. 3'', ''Fire Emblem'' | | ''Super Mario Bros. 3'', ''Fire Emblem'' | ||
| By limiting one of the scrolling axes to only 2-screens wide, this makes unlimited scrolling in the other axis | | By limiting one of the scrolling axes to only 2-screens wide, this makes unlimited scrolling in the other axis simpler. With unlimited horizontal scrolling there will be unavoidable attribute glitches at one side of the screen (see ''Super Mario Bros. 3''), but with unlimited vertical scrolling this can be hidden by [[overscan]] in NTSC regions (see ''Fire Emblem''). | ||
|- | |- | ||
| Unlimited Bidirectional | | Unlimited Bidirectional | ||
Line 57: | Line 171: | ||
The best way to understand the mirroring techniques used in a game, use a debugging emulator to look at the nametables. [[Status bar|Status bars]] typically require a scrolling split at a timed location on the screen. This can be done most easily with a mapper based [[IRQ]], but can also be accomplished with a [[sprite-0 hit]] or other techniques. | The best way to understand the mirroring techniques used in a game, use a debugging emulator to look at the nametables. [[Status bar|Status bars]] typically require a scrolling split at a timed location on the screen. This can be done most easily with a mapper based [[IRQ]], but can also be accomplished with a [[sprite-0 hit]] or other techniques. | ||
Latest revision as of 14:49, 17 April 2017
This is my proposal for a new scrolling page. Some information which is currently on the mirroring page should be moved here. On the other hand, complex scrolling techniques are moved to a new scroll split page. Feedback and constructive critisism is welcome.
Sections Unidirectional scrolling and Mirroring chart were just moved arround, other sections were significantly altered by myself (Bregalad).
!! CURRENTLY THIS PAGE IS A WORK IN PROGRESS !!
Scrolling is the movement of the displayed portion of the map. Games scroll to show an area larger than the 256x240 pixel screen. For example, areas in Super Mario Bros. may be up to 24 screens wide. The NES's first major improvement over its immediate predecessors (ColecoVision and Sega Mark 1) was pixel-level scrolling of playfields.
Unidirectional scrolling
Ordinarily, a program writes to two PPU registers to set the scroll position in its NMI handler:
- Find the X and Y coordinates of the upper left corner of the visible area (the part seen by the "camera")
- Write the X coordinate to PPUSCROLL ($2005)
- Write the Y coordinate to PPUSCROLL
- Write the starting page (high order bit of X and Y) to bits 0 and 1 of PPUCTRL ($2000)
The scroll position written to PPUSCROLL is applied at the end of vertical blanking, just before rendering begins, therefore these writes need to occur before the end of vblank. Also, because writes to PPUADDR ($2006) can overwrite the scroll position, the two writes to PPUSCROLL must be done after any updates to VRAM using PPUADDR.
By itself, this allows moving the camera within a usually two-screen area (see Mirroring), with horizontal and vertical wraparound if the camera goes out of bounds. To scroll over a larger area than the two screens that are already in VRAM, new tile and attribute data decompressed from leve data has to be filled in the nametables, as seen in the animation below. The area that needs rewritten at any given time is sometimes called the "seam" of the scroll.
Frequent pitfalls
- Taking too long
- If a NMI handler routine takes too long and PPUSCROLL ($2005) is not set before the end of vblank, the scroll will not be correctly applied the following frame. Most games do not write more than 64 bytes to VRAM per NMI, more than this may require on NTSC consoles advanced loop unrolling techniques to fit the narrow window of time offered by the VBlank period.
- Set the scroll last
- PPUSCROLL ($2005) must always be set after using PPUADDR ($2006). They have a shared internal register and using PPUADDR ($2006) will overwrite the scroll position.
PPU registers
When split scrolling is required, some more advanced usage of $2005 and $2006 registers is needed. The complete information is is on a separate page : split scrolling.
Multi-directional scrolling techniques
Scrolling in a direction in which the screen is not mirrored is usually easy, since there is a whole screen of buffer space to update data. On the other hand, dealing with scrolling updates is harder when the axis in the direction it is scrolled to is mirroring, because graphics leaving one side of the screen directly enters the other side.
The rarely-available L- or X-shaped mirroring could facilitate changes in scrolling direction on screen-boundaries without having to flip between Horizontal and Vertical mirroring.
Horiontal scrolling with horizontal mirroring
Doing any horizontal scrolling using horizontal mirroring is hard to do smoothly because the data on the right of the screen is immediately show on the left due to mirroring. Clever use of hardware left-side screen clipping will hide all name table glitches, but because the attribute tables have a resolution of 2x2 tiles, there will always be attribute glitches on the left and/or the right side of the screen. Some televisions overscan up to 8 pixels on both left and right border, but most doesn't. PAL NESes will automatically clip the left and right 2 pixels. Several solutions exists:
- Ignore the problem: Colour glitches are accepted, and are minimized (see below)
- Work arround the problem: Levels use only a single palette (as implemented by Wizard & Warriors II), or have a level design where the colour scheme repeats itself vertically each screen. This seriously reduces the graphical possibilities.
- Fix the problem: Overlay 8 additional pixels of BG with sprites. This can be either solid-colour sprites designed to hide bachground graphics (as in the game Alfred Chicken), or sprites reusing BG graphics and correct colours instead of the incorrect colour from the attribute table. Very few games do this because it reduces the number of (actual) sprites per scanline to 7 and wastes a lot of OAM space (roughly 1/4 in 8x16 pixel sprite mode).
If glitches are accepted they appear to at least 7 pixels due to techincal reasons (assuming left-clip is enabled via $2001). Several strategies exist however to make them less blatant:
- Make the various BG palettes use the same luminosity pattern and only changing the hues, that way the area will be wrong colored will at least have correct luminosity, and as such, look less wrong.
- Make the glitches in the direction the player is not facing (as seen in Kirby's Adventure).
- Share the glitches on both borders, so the total area of graphics showing with the wrong colour will be minimized. For example 4 pixels on the right side and 3 pixels on the left side. On PAL consoles, this will reduce to 2 and 3 respectively.
Games with such glitches typically does a poor job at minimizing the amount of glitches, so they give a bad impression as to what is actually possible.
This diagram shows how the glitches can be minimized for a 16-pixel horizontal scroll cycle, each line representing a different fine horizontal scroll value.
Fine HScroll 0 --------|------------------------ 1 #-------|------------------------ 2 ##------|------------------------ 3 ###-----|------------------------ 4 ####----|------------------------ 5 #####---|------------------------ 6 ######--|------------------------ 7 #######-|------------------------ 8 ~~~~~~~~|------------------------ (NT update) 9 #~~~~~~~|~----------------------- 10 ##~~~~~~|~~---------------------- 11 ###~~~~~|~~~--------------------- 12 xxxx----|--------------------~~~~ (AT update) 13 xxxxx---|---------------------~~~ 14 xxxxxx--|----------------------~~ 15 xxxxxxx-|-----------------------~ 0 --------|------------------------ (NT update) ^^^^^^^^ ^^--- Hidden on PAL machines Hidden part (by hardware through $2001) - Correct tile displayed with correct colorus ~ Correct tile displayed with wrong colours x Wrong tile displayed with correct colours # Wrong tile displayed with wrong colours
Vertical scrolling with vertical mirroring
Because data that is on the top/bottom of the screen will immediately show up on the other side, a clever use of NTSC overscan can make it glitch-less multidirectional scrolling, but glitches will appear on PAL televisions (and NTSC televisions with a overscan range which is a little off). Because the vast majority of commercial games were developped in NTSC countries, they tend to consider the vertical overscan as a safe buffer zone for scroll updates.
However, as with the case of horizontal scrolling with horizontal mirroring, it is desirable to minimize the unavoidable glitches. The best possible way to hide glitches is to make 4 pixels with wrong tiles and 4 additional pixels with wrong color on both sides. Games with such glitches typically does a poor job at minimizing the amount of glitches, so they give a bad impression as to what is actually possible.
Perfectionist programmers could use raster split to hide glitches, and possibly also provide more blanking time to update VRAM as well as hiding the unavoidable sprite poping in the top border. This is seen in the games Jurassic Park and M.C. Kids, but it was rarely done because it complicates the code a lot for little benefits.
This diagram shows how the glitches can be minimized for a 16-pixel vertical scroll cycle, each column representing a different fine vertical scroll value.
Fine VScroll 0123456789ABCDEF0 -###~~~~-xxx----- < Hidden by --##~~~~--xx----- < NTSC average ---#~~~~---x----- < Overscan ----~~~~--------- < -----~~~--------- < ------~~--------- < -------~--------- < ----------------- ----------------- ----------------- ----------------- ----------------- ----------------- ----------------- ----------------- ----------------- < --------~-------- < --------~~------- < --------~~~------ < ----x---~~~~#---- < ----xx--~~~~##--- < Hidden by ----xxx-~~~~###-- < NTSC average ----xxxx~~~~####- < Overscan ^(NT update) ^(AT update) ^(NT update) - Correct tile displayed with correct colorus ~ Correct tile displayed with wrong colours x Wrong tile displayed with correct colours # Wrong tile displayed with wrong colours
Status bars and single-screen mirroring
Single-screen mirroring's main advantage is that it allows using a status bar at the top or bottom of the screen while also allowing the playfield to extend equally in any direction. Typically the status bar is stored in one nametable and the playfield in the other. Scrolling parameters and nametables are switched the appropriate screen location during rendering.
Due to the screen layout being entierely linearly adressable, the calculation of PPU addresses of name and attribute tables updates are significantly simpler, leading to typically faster, more efficient scrolling routines. A variable sized or self-scrolling status bar can relatively easily be created thanks to 1-screen mirroring.
The same graphical glitches as discussed above under horizontal mirroring will happen. However, as long as there is a status bar, glitches are fully avoidable vertically since the data that falls off the bottom (or the top) of the screen will come in the area that is "hidden" by the status bar, regardless of overscan factors.
Mirroring chart
This table lists the most common mirroring and scrolling techniques. There are a huge variety of more complicated techniques. For a more comprehensive survey, see: List of games by mirroring technique
Scrolling Type | Mirroring | Example Games | Comment |
---|---|---|---|
None | Any | Donkey Kong, Tennis | With only a single fixed screen, any mirroring type can be used. |
Horizontal Only | Vertical | Super Mario Bros., Gimmick! | A status bar at the top is easy to accomplish with a sprite-0 hit (see Super Mario Bros.). |
Vertical Only | Horizontal | Ice Climber, Gun.Smoke | Without a status bar, horizontal mirroring is the best choice for vertical-only scrolling. With a status bar, vertical or single-screen mirroring gives a place in the nametable to render the status bar, and the scrolling seam should be hidden under the bar. |
Alternating Horizontal/Vertical | Mapper switches H/V | Metroid, Air Fortress | Motion is limited to a single axis at any given time, and the direction can only change when a new screen is reached. |
Limited Bidirectional | Horizontal/Vertical | Super Mario Bros. 3, Fire Emblem | By limiting one of the scrolling axes to only 2-screens wide, this makes unlimited scrolling in the other axis simpler. With unlimited horizontal scrolling there will be unavoidable attribute glitches at one side of the screen (see Super Mario Bros. 3), but with unlimited vertical scrolling this can be hidden by overscan in NTSC regions (see Fire Emblem). |
Unlimited Bidirectional | Various | Castlevania II, Battletoads, Crystalis, Final Fantasy | Unlimited scrolling in both axes at once is an advanced technique requiring a game-specific solution. |
The best way to understand the mirroring techniques used in a game, use a debugging emulator to look at the nametables. Status bars typically require a scrolling split at a timed location on the screen. This can be done most easily with a mapper based IRQ, but can also be accomplished with a sprite-0 hit or other techniques.