How to make raster effects on the NES ?

by Bregalad

In order to enhance graphics available for the NES, it is necessary to do "mid-frame" effects, that is changing the status of some graphics registers while a frame is rendered.

Because televisions standard have an implementation where the pixels are rendered like text, from left to right then top to bottom, it's possible to change paramters in the middle of the screen so that the area above the split have some parameters and the area below some other parameters. Understanding this may not be always be easy but it crucial in getting good effects for games and get rid of some limitations the system normally imposes to the programmer.

While many doccuments are available on the net to explain such behavior, many may turn newbie grame programmers off as they are almost always written in the emulator author's viewpoint, and never in a game programmer's viewpoint. I consider knowing at what exact clock cycle a latch inside the NES change it's state is not meaningfull to game programmers, but knowing how to put such a behaviour to good use is.

It is assumed that the readed already knowns a bit about the NES architecture, PPU registers, tiles, nametable and a bit about scrolling. If you don't know what I'm talking about you should first check other doccuments that covers basic graphic rendering for the NES. It is not necessary to read the whole doccument to understand the concept. You can go straight to the end if the middle does not interest you. This doccument ended up *much* longer than whan I exepted to write at first, but since I wrote it I don't want to just delete it.

This page explain the concepts under the many effects possible with this, along with a demonstation on how to use that to have a status bar that is fixed while the gameplay screen is scrolling. It is assumed that the reader knowns a little about the NES, but it was written to be newbie-friendly, so that very newbies for the NES can understand how some effects are done, and do some of them in their games/demos.

Content list :

About scanlines

I won't go into details here, because deatails are rarely relevant when doing a game or tech-demo, they are for emulator writters. Some doccuments I've found gives headache informations about how the NES renders scanlines. I took the time to rewrite the informations so that a simple guy wanting to write a game can figure what's going on easily without spending too much time for useless details.

List of possible effects

A "raster effect" is any graphical effect, that could be extremely simple or absolutely uncredible, that changes the state of the PPU between scanlines through registers. I refer the point where the state is changed as a "split point". Also, it's possible to have many split points. Up to 240 in theory, but more on that later.

The PPU has 8 registers, ranging from $2000 to $2007. I will mention what is possible for each register.

Mid-frame effefct possible with $2000

Changing nametable

Bits 0&1 of $2000 are the 9th scrolling bit, so you'll have to see below in the scrolling section for details. By changint the bit $2000.0, it is possible to change the nametable displayed at any time. You can get interesting effects with that.
For example if both nametables show similar data but there is a difference somewhere, you can do some effects to the place where the graphics changes, without alterning the rest of the screen. You can also have the same nametable in both tables, but a different attribute tables, and this enables fun effects with the color of objects on the screen, or get transparency effects.
However, changing $2000.1 has no direct effect. This implies that this kind of effects require vertical mirroring.

Changing patterns

Bits 3&4 contols which pattern tables are used for BG and sprites. It is also possible to change them anytime in the frame, so that the patterns used to draw the graphics changes from one scanline to another. This can also lead to many effects.
For example if the pattern in both tables are close but with a different luminosity you can get transparency effects.
But the main purpose of this is to bypass the 256-tiles limit for either BG or sprites, at the expense of the other.

Changing sprite mode

It is also possible to change bit 5 of $2000, so that the sprite size (8x8 or 8x16) is changed in the middle of the screen.
This is not really recommanded, as it may have weird effects at the time you switch. In addition to this, you cannot get really awesome effects out of it as far I know. You could get 8x8 sprites for the status bar and 8x16 for the gameplay (or the other way arround) and this could be usefull. If you do that be sure to text it extensively on the real hardware.

Disabling interrupts

Not really an effect, but by changing bit 7 of $2000 you can disable VBlank interrupts. You can do that anytime if you don't want your code to be interrupted, as the "sei" instruction does not prevent VBlank NMIs from happening. However, when writing a value with bit 7 set again to $2000, it may be possible that you missed an interrupt.
If the VBlank has not ended yet, an interrupt will start right after the write, and for consequences the timing will not be the same as usual. It may be possible that the VBlank updates to the PPU works normally, but not in this case because the interrupts fires later. So in doubt, read $2002 before enabling interrupts back to be sure that no interrupt will fire staight away.
All other bits of $2000 are not usefull to change midframe as far I know.

Mid-frame effects possible with $2001

Changing color emphasis

Bit 0, 5, 6 and 7 of $2001 can allow you to use gray-scale mode and color emphasis. It can be changed anytime in the frame and take effect immediately. Not only you can get some graphic effects with that, but it is very usefull to see how much time a routine you wrote takes. Or you can see how much the CPU is busy by setting this bit while it is busy, and clear it afterwards. By seeing how large the gray band is, you can instantly make your conclusions.
You can get great transparency effects by setting both grayscale and emphasis. Also, it is not only possible to change this bit mid-frame, but mid scanline, so that the left part of the screen is gray and the right part is normal. Unfortunately the CPU is much slower than the PPU, so the gray bar will be shaking a lot and you cannot get any precision in doing that.

Changing sprite or Background enable

Bits 3&4 of $2001 can be changed anytime to display or hide background and sprites. They take effect immediately.
As long as you only hide background or only sprites, this can lead to interesting effects (such as disabling sprites on your status bar). However, if you set both of those bits to '0', the PPU will stop function as usually, and will enter in it's "Forced VBlank" mode. Normally, only the background color (the color you write at $3f00) is seen in this mode.

Forced VBlank mode

This mode allows the screen to be blanked constantly, and normally when starting your programm the first thing you do without knowing is entering in this mode by writing $00 to $2000 and $2001. You can write to $2006 and $2007 as if it was in VBlank. By cleverly blanking areas of the screen while leaving other areas enabled, it can lead to heavy patterns/name table uploads in order to get some effects. It is also possible to rewrite the pallette that way. But be warned that if you set $2006 to adress a palette, that color will be seen on the screen instead of the background color. This can lead to interesting effects, but can be undesirable if you only wants to change the palette. Also, blanking the screen is the *only* way to change the palette midframe. You cannot get a lot of colors on the same screen unless you blank the screen midframe.
If you ever do this kind of effects, be sure to extensively test on the real hardware.

Important : While in forced blank mode, the scrolling counters are not updated, the OAM DRAM is not rereshed, and the Palette DRAM is not refreshede either. For consequences, when you enable the rendering back, the scrolling will be erased and be set to some impredicible values as you wrote to $2006 (see below for details).

Another important thing is that the PPU still sends a background color to the screen and continue to exectute VBlank interrupts normally in that mode, even if the screen is contantly "blanked".
The only way to directly render a proper frame when enabling the screen back is to enable VBlank NMI (but *not* enable the rendering), and set proper scroll values, OAM and palette in this NMI, along with turning normal rendering on via $2001.

Mid-frame effects possible with $2002

$2002 is a read only register, so you can't directly do effects with it. However, reading it is a key in doing mid frame effects.

VBlank Flag

$2002.7 tells you if you are in VBlank. This flag is set to '1' when a VBlank period starts (at scanline 240), it is clear to '0' when the VBlank period stops *or* when you read the $2002 register. As a consequence, if you read a '1' to this flag, it will automatically read '0' the next time. This flag is used to decide whenever a NMI fires (if enabled via $2000.7), and read it acknownledge the NMI. You must read $2002 in your NMI routine to acknownledge it.
In theory, you could have many NMI sources and if $2002.7 is clear on the NMI you know it's from another source. However the only other possible source is the almost never used expansion port on the bottom of your NES. So it is usually assumed any NMI is triggered from $2002.7 without any further check.

Reading $2002 at the exact time of a VBlank start will clear the flag *and* return a '0' in bit 7, implying you missed a VBlank. For that reason if you don't want to randomly miss frames, you should not poll $2002, but use NMIs instead.

Sprite zero hit

$2002.6 is a very interesting flag. This flag is always cleared on the start of a new frame (at the end of the VBlank), and is set as soon as we reach a non-transparent pixel from the sprite zero that hits a non-transparent pixel of the background. Sprite zero is the first sprite found in OAM. By placing the sprite at the good place, you just have to check this flag by reading $2002.6 By checking regularly, when you detect a '0' to '1' transition, you know the rendering is exactly where you placed your sprize zero, and you can start doing effects.
The only problem is that you can only get one sprite zero hit per frame. So you can only synchronize your code with the PPU 3 times per frame : one time for the VBlank NMI and the second time with the sprite zero hit. You can also synronize by detection '1' to '0' transitions of this flag to know when a VBlank is about to end, but it's not that interesting, as you already synchronized on the beginning of VBlank normally.

At least one pixel should "hit" so that this flag becomes true, if no pixel hits, it will remain clear forever, and in some cases, this will lead your programm to freeze, which is a *bad* thing. Also I'm pretty sure that the hit shouldn't happen on the far right of the screen, else it will be ignored for some reason. It shouldn't happen inside the left-most clipping area if left most clipping is enabled via $2001 (for either BG or sprites, because there is no hit). It's important to respect that rules. It's the imagination of anyone to hide the sprite zero so that it's not visible, or barely visible.

Sprite overflow flag

$2002.5 is also interesting. It is clear on the beginning of each frame, and it set as soon as more than 8 sprites are met on the same line. As you may know, when more than 8 sprites are supposed to be seen on the same line, the NES discards the lower priority sprites, and they won't be visible.
When that happens, this flag is set, and once set it remains set until the end of the frame. You could use that flag to synchronize with the PPU, for example you can put 8 sprites on the bottom of the status bar (wich is at the top of the screen) on the same line, and rely on a '0' to '1' transition to synchonize with the PPU without a sprite zero hit. However, I've heard that this flag is unreliable I don't really know why. So if you do something like that, you must test extensively on the real hardware

Abusing the 8 sprite per line limitation

Not really an effect with $2002, but something interesting while we're on the topic. If you want to disable some sprites on some scanlines, but that you don't want to disable all sprites, or if you just don't want to have a code that synchronize with the PPU, or both, you can actually rely on the 8 sprites per line limitation to hide your sprites. However, many people will play your game/demo with the sprite limit disabled on their emulators as this limit is often more annoying than usefull, so you'd have to mention it in your doccumentation.

Mid-frame effects possible with $2003/$2004

If there is any registers on the NES which are really obscure even many years after the console was first reverse-enineered, it's without a doubt $2003 and $2004. You can most likely not get interesting effects by writing to $2003 and $2004 during the frame, and it will probably just add glitches to your sprites, but I can't give a 100% guarantee on that.

However, as $2003 is write only, $2004 can also be read. During VBlank this allows you to read back what you wrote in OAM, but I really see no point in doing that. During the frame, the PPU will have to read sprite data from OAM, and while doing that, the data read is also mirrored in $2004. Unfoturnately, the CPU is much slower than the PPU, and the chances of putting that to a good use are slim.

It has been recently discovered that by using many sprites made of all $00 (using tile zero, color zero, all flags to zero, and X position to zero) on the same Y position, you can syncronize with the PPU by reading $2004 and looping until your read the value $00. However I'm not sure how reliable this is.
You could get false positives (read the value $00 before exepted), so to prevent that you want to make sure all other sprites are never placed at X=0, are never using tile $00, and that if their color is zero then another flag should be turned on (vertical flipping, horizontal flipping or behind background), so that all values for other sprites are never $00. In addition to that, you may also loop until two consecutive $00 are read from $2004, I'm not exactly sure about that.

Finally, as this have been discovered recently, and no emulator, even the most accurate ones, really implement this proprely yet. Most emulators will just read OAM back via $2004, even during the frame, so you'll get only a small delay before you think the PPU has reached the point where you zero sprites are placed.
This could also work with another value than $00, but that value should not change when and-ed with $e3, as the flags are not all implemented in OAM, and writing $ff to it and reading it back will read $e3. Also, other values should be hard to avoid for other sprites. But for $00, any sprite at position $00 is useless if left-clipping is turned on, so the only true limitation is that when using color $00, another flag have to be turned on.
If you do any tricks using $2003 or $2004, you want to test it extensively on the real hardware.

Mid-frame effects possible with $2005

Changing horizontal scrolling

Writing to $2005 midframe will, simply put, change the horizontal scrolling. Writing a second time to it will *not* change the vertical scrolling, it will get ignored. Writing a third time will change horizontal scrolling again, etc... You can read $2002 to make sure your next write is the horizontal one. Contrary to popular belief, after a horizontal write there is absolutely no need for a second dummy $2005 write, it works perfectly with only one write.
Combined with $2000.0, it is possible to change the scrolling to any horizontal position possible.

Unwanted effects

Writing to $2005 mid-scanline can get undesirable glitches on the screen. In order to change the scrolling without any glitches, you want to experiment trial and error by adding or removing some NOPs before your $2005 write, and fine tune your timing until you get a setup with no glitches.

Mid-frame effects possible with $2006/$2007

Set scrolling to a fixed value

$2006 writes, are much more interesting, and you can get really good effects. Most other docs say complicated things about it, but on the programmer's side it's really simple, and they are the reason I wrote all of this. When you want to write something to the PPU memory, you write an adress to $2006. Writing an adress during the frame will simply make the corresponding name table tile show up on the left of the next scanline. This allow you to change both vertical and horizontal scrolling, but with a resolution of 8 pixels. For example, if you write $21 then $40 to $2006, the scrolling will be affected in a way so that the tile at adress $2140 will immediately be shown on the far left of the next scanline. You don't even have to compute which scroll value this corresponds, and this is really usefull.

Fine scrolling

The higer 2 bits allows you to increase the resolution. In the example above the mentionned tile will be shown, but will be scrolled 2 pixels down, because the higher 2 bits says '2'. If you wrote $01 then $40, the same tile would be shown, but it won't be scrolled, it will be shown from the top. It's then impossible to scroll lower than 3 pixels, writing $41 then $40 has the same effect than writing $01 then $40, it won't scroll 4 pixels down (you could say the bits 14 and 15 of the adress have no effect at all).

Because of this fine scroll feature, there is no way you can trick the PPU and use pattern table data as name table data by writing an adress that is between $0000 and $1fff, it will point to nametables with a different fine scroll value (it's such a shame). However, you can trick the PPU by using attribute table data as name table data, by writing an adress between $x3c0 and $x3ff. Sadly, it will also be used as attribute at the same time, which is not practical. By setting all 4 background palettes to be identical, it could become more usefull.

Undesirable glitches

Writing to $2006 mid-scanline can get undesirable glitches on the screen. In order to change the scrolling without any glitches, you want to experiment trial and error by adding or removing some NOPs before your $2006 writes, and fine tune your timing until you get a setup with no glitches. Sometimes it even seems hard to come with no glitches at all (also many emulators won't show glitches when they actually are there, you must test under an accurate emulator or the real hardware).

Multidirectionnal scrolling

By writing to $2006, $2006 then $2005, you can set the screen to a known vetical position, and then set the desired horizontal scroll. If you do that, I recommand the you write a correct horizontal position with $2006 as close to it's $2005 counterpart, and then write the $2005 scroll so that you get rid of the 8-pixel resolution limit. This seems to avoid glitches, altough I'm not exactly sure why. A $2000 write is never needed when doing that, as you chose the used nametable with $2006.

If you do not do a write to $2005, the fine horizontal scrolling seems to be unaffected by $2006 writes. For example if you write $21 then $40 to $2006, and that the previous horizontal scrolling value written to $2005 was $34, the tile at adress $2140 will be shown on the left-most border on the next scanline, but the tile will be scrolled 2 pixels down (as mentionned above) and 4 pixels right (because the fine scrolling is not affected by the $2006 writes).

About $2007

As far I know acessing $2007 during the frame is a *bad* idea and will only introduce glitches in your graphics. Writes will *not* have any other effect than glitching your graphics, even during HBlank. You must use "forced blanking" mode mentionned above, even if it's for a very short time.

Bankswitching CHR midframe

If you use a mapper with CHR bankswitching, it's possible to bankswitch your CHRROM or CHRRAM midframe so that you can get rid of the 256 tiles limit for both the background and sprites.
In addition to have more tiles, you can also bankswitch similar but different patterns in order to get transparency effects or things like that. Or you could bankswitch a CHR bank which contains all zeroes to simply disable some backgrounds or some sprites, but not all of them.

Practical use

You get nothing for nothing

While most of those effects are cool, it is very impractical to do full screen effects in a game, simply because it would take 100% of the CPU time, leaving no time to do any game logic. Also, it's only possible to synchronize with the PPU 3 times per frame under standard conditions (VBlank, end of VBlank, sprite zero hit), and the two latter relies on the fact that there is a sprite zero hit, and are not suitable for all cases. To get more than one split point per frame, you'll have to write timed code from one synchronized point, and while this can be fun it's tedious to do.

The NES by itself only has 2 IRQ souces, DMC and APU frame, both are not syncronized with the PPU but with the APU, and both are mostly useless. Only external IRQs (from the cartridge) are really usefull, but you have to use a mapper that supports them. With such a mapper, it's much less tedious to get effects, as you can synchronize with the PPU more easily under some conditions.

Synchronizing with the PPU

As mentionned above, you'll need a reilable source of syncronisation. The easier to use is the sprite zero hit, that you have to set up in a way so that it does collide with background. Remember that all color #0 pixels are considered transparent, no matter if this is a BG or Sprite tile. A non-transparent BG pixel has to collide with a non-transparent sprite #0 pixel so that the flag at $2002.6 get set to '1'. Once set, it is only clear to '0' at the end of VBlank, so at scanline 0.

Synchronizing at VBlank :

NMI ;Pointer at $fffa points here
pha
txa ;Do never go away without first saving the regs
pha
tya
pha
bit $2002 ;Acknownledge the interrupt
...... ;You know you're at stanline 240 here if the 'N' flag is set (it normally always will unless another NMI source exists
......
pla
tax
pla
rti ;Depending on your coding style, you may or may not still be in VBlank here

Synchronizing at scanline 0 by detecting a '1' to '0' transition :

;It is assumed the sprite zero hit flag is already set here
- bit $2002
bvs -
;When the CPU goes outside of that loop you know we're at scanline 0

When the flag has a '0' to '1' transition, we know we're at the location of the sprite 0 :

;It is assumed the flag is alreday clear here
- bit $2002
bvc -
;When the CPU exits the loops, we know we're at the location of the first pixel that makes the collision

Because a bit / bvc loop takes 7 clock cycles to complete, you can exit the loop in a 7 clock cycle window without moving the sprite zero at all and this is normal, you'll have to deal with that. An IRQ or NMI also can trigger in a 7 clock cycle window as some 6502 instructions takes up to 7 clock cycles to complete (altough they are rare).

Writing timed code

If you want more than one split point, it will be necessary to write some timed code. This will allow cool things like changing the state of some registers each scanline (not just once) so that it does cool effects. You will just have to remember a few points when writing timed code :

To handle the fractionnal clock cycles

A convenient way of doing it is that in each iteration of the loop you have something like that :

lda var
clc
adc #$ab
sta var
bcs + ;This instruction takes almost exactly 2 + 2/3 clock cyles for NTSC timed code
+ ....

lda var
clc
adc #$90
sta var
bcs + ;This instruction takes exactly 2 + 9/16 clock cycles for PAL timed code
+ .....

Var does not need any initialisation but should not be touched by the rest of the loop. This is not the *only* wat to do this, but I find it's one of the most convenient. Feel free to come with your own ideas in your game/demo.

To adjust the starting point of the loop

Often after a sprite zero hit (or an IRQ) you do not want to start imediately the loop (or even a single split) doing mid-frame writes to the PPU registers. Reason for that is you're likely to get glitches, and by finding a way to make it happen later or sooner, by trial and error you will be able to get rid of the glitches. There is no instruction that can take one single c.c., but nop takes 2 and lda zeropage takes 3. So in order to adjust the loop you'd want to add something like that :

nop
nop ;Takes 4 cc., but too early
.....

nop
nop
nop ;Takes 6 cc., but too late ?
.....

lda $ff ;Dummy read that will not matter
nop
nop ;Takes 5 cc. -> get more precision and make your conclusions
......

Longer delays

If you want longer delays than just a few cycles (like if the sprite zero is always some scanline above the desired split) you do not want to have a long useless chain of nops. Instead just write a loop like that :

ldx #Constant
- dex
bne -

And adjust your constant with trial and error. Increasing the constant of 1 means 7 cc. of more delay. You must follow this loop by the nop technique above to fine-tune the timing within 6 c.c. Also, when converting from NTSC to PAL, multiply the constant by 15/16. When converting from PAL to NTSC, mulitply the constant by 16/15.

Warning about some evil instructions

Some instruction takes a variable number of clock cycles when a "page boundary" is crossed (if the high byte of the destination adress is changed).

For example :

ldx #$00
adc $6ff,X ;Takes 4 clock cycles
inx
adc $6ff,X ;Argument is located at $700 but takes 5 clock cycles instead of normal 4

Also :

$efff: lda Var
$f001: bmi $efff ;Here the BMI opcode if the branch happen is 4 cycles instead of normal 3.

Be sure to avoid such instructions, and if you use them, find a way to make sure they do never (or always) cross a page boundary so that your timing is not screwed up.

Also, the DPCM channel must be incactive (turned OFF via $4015.4) when doing such effects else your timing will be screwed as well.

How to make a status bar

While most people writing tech-demoes will want to use all possible effects to show off, when writing an actual game, the really usefull thing is to have a status bar that does not scroll, while the gameplay screen does. Doing it horizontally is very easy, as all you really need is a sprite zero hit, detect a '0' to '1' tansition, and have one $2005 (and possibly $2000) write to change the scrolling.

Doing it vertically is much harder, as you have to deal with $2006. I wrote two demos that show how to have vertical scrolling with a status bar, one which have the status bar at the top, and another that have it at the bottom.

Status bar on the top demo

Having a status bar on the top is a good choice, because you can use the syncronisation from the VBlank to deal with the graphics, wait a little while until the split point, and after the split return to the main game engine. The interruption of the game engine are longer than if there were no status bar, but there is still most of the CPU time dedicated to the main engine, so it is very usefull when writing games. If a game frame were to take longer than a rendered frame, the VBlank and split would happen as supposed, and nothing really bad would happen (exept that the programm will slow down).

In addition to that, it's usually easier to deal with sprites if the status bar is at the top. You can let sprites overflow in the status bar and this won't look weird. If you really don't like it, you can disable sprites before the split point and you're done.

The main inconvenient is that when scrolling vertically, you have to use $2006 in a complicated way and you can't get full resolution with that. Scrolling by 8-pixel increments can work for fast scrolling, but not always for gameplay.
It is however possible vary the position of sprite zero, so that the position where you write the coarse scrolling itself varies in function of the fine scrolling and everything scrolls smoothly.
At the split point I also turn the background off, and I wait 8-n lines where n is the fine scrolling, and enable the background again. That way, the background is always enabled on the same scanline.
This effect isn't hard to do but I understand it may turn some newbies off, so that's why I made a demo for that.

Status bar on the bottom demo

The main advantage of having the status bar on the bottom is that you only need two simple $2006 writes in order to make it appear after the split, and there is no need for any timed code or complications.

The problem is that the status bar being small, it's hard in an actual game engine to exectute all gameplay code only after the split point. It would slow down all the time, while the main CPU would do nothing about 80% of the time, and this is just a ridiculous situation.
Then it becomes necessary to place gameplay engine between the VBlank and the split point. While it's not a problem in itself, the problem is that there is no way to redirect the sprite zero hit to an IRQ (unfortunately), so the only way to detect it is constant polling. So if your game engine is getting too slow and the frame does not end before the split point, you're rotten and will not detect the sprite zero hit before the next frame. Not only the game will slow down, but the status bar will only be split one frame out of two, resulting in terrible flickering. This happens in some commerical games tough, but looks really terrible. The only solution is to make sure you game engine never slows down at all, and always ends before the split point even in worse situations.
You could use the DMC IRQ to get an approximate shot above the sprite zero hit, and poll the flag in the IRQ routine. I don't know how well this works, but it sounds fine.

The second problem is that the sprite zero hit must happen on the playfield. On the status bar it's not too hard to get one, but on the gameplay field yes, because you never know when a tile that only have transparent colors slips on your sprite zero, resulting in a game freeze. In order to overcome this problem, I came with a clever solution. I always use a different tile where the sprite zero hit is supposed to happen. However, this really looks ugly. With CHR-RAM, it's possible however to get the graphics of the tile that would normally be there, to modify it so that there is no transparent pixels on the line where the sprite zero is, and to write it to the special tile. This is not too complicated to pull of in a demo as the name table and pattern table data is stored "as it", but it would be much more complicated to pull of in an actual game, because you have to get them from the level which sounds tedious.

Download the demoes

So both demoes does only a small trick to get a status bar either at the top or the bottom with vertical playfield scrolling, without using any speical cartridge hardware. The use graphics from Castlevania III - Dracula's Cure by Konami, because it would have taken too long to make my owns.
The sources are available and should be compilable using WLA-DX. The sprite zero is a white dot and I made it visible for educationnal purposes. If I were to actually release a game/demo, I'd make it as hidden as possible.
Download from Here.

Concliusion

I hope this doc helped people that wanted to do a programm that does some complicated graphics tricks on the NES but did not want to go through the headache of the un-necessary stuff. It covers most aspects of raster effects on the practical/coder's side and not from the emulator author's side. It explans how to exploit the effects, not what they are due to. I hope this have been usefull to you.

I'd like to thanks all active members of NESdev, as without them I wouldn't have the knownledge to write that, even less to understand the "headache doccuments" for the emu author. (I hope this one wasn't too much a headache for you). If you have any quesiont, please contact me via the Nesdev BBS for any questions or comments.

Valid HTML 4.01 Transitional