I have not seen a lot of information on this, but what I'd like to do (and I think I have heard is possible) is swap out the background palettes mid-frame, thereby separating the status bar from the playing field palettes. Just to note, I have divided the screen with a sprite 0 hit between the status bar and the playfield (allowing scrolling for the former, thanks Tokumaru!).
Besides the increased amount of color on the screen, my other goal is to be able to fade the playfield to black and move the player position between screens (in other words, faux flick-screen scrolling). I have this opeational, but the status bar currently must fade out as well. Besides a mid-frame palette change, which would allow the playfield to fade to black while preserving the status bar, is there another way to accomplish this same effect?
Thanks for any help!
I don't really know anything about the NES, but if it's anything like the SNES, you change colors, not whole palettes at a time. I don't know how fast the NES can change colors, but what you could probably do for status bar is to have about 8 pixels vertically that are solid with one color so you can change 3 of the colors in that space, and then at the edge, you change the color of the bar to whatever you want it to be. I don't know how fast the NES can change colors, but I imagine it can do that.
The NES requires that you turn off rendering to change the palette.
The strictest example of this is the title screen for Indiana Jones at the Last Crusade:
viewtopic.php?p=139925#p139925 – they disable rendering for the rightmost ~20 pixels in order to change just one palette entry. You won't be able to do better, and you can only change the backdrop color this way. (It'll be visible as a dancing patch of color otherwise).
Less strict: You can change approximately 4 or 5 colors given one empty scanline, but the color of that blank scanline will be one of the colors you're replacing. See
viewtopic.php?f=21&t=12299Most aggressive: A fully-unrolled loop in RAM could replace all 13 colors of the backdrop in two scanlines, but your choice of either a smear of color or some odd greys will be visible. See also ccovell's demo
Sayoonara!.
Least visible: You can change 6 bytes out of the 32 locations of palette RAM every scanline, minus three on both the first and last scanlines. Subtract two if you want to choose the color that will be visible on that scanline.
Mid-frame palette changes are very tricky, because rendering has to be disabled so the PPU can be written to, and when rendering is off and the VRAM address is pointing at the palette area (which it will be, since you'll be changing the palette), the colors being pointed at get displayed on the screen, instead of color 0.
This causes a "rainbow" to be displayed on the screen, which looks like a glitch. This can be minimized with the grayscale bit, so you get grays and white instead of colors, but that's not much better. To fully prevent glitches, you have to make sure that the VRAM address is only pointing at the palette area during HBlank, so you can realistically change about 2 colors per scanline.
If that's not a problem, and you can live with a few blank lines between the playfield and the status bar, just disable rendering (as close to the end of the scanline as possible, to avoid sprite corruption on the next frame), time your code so that the VRAM address is never pointing at $3F00-$3FFF during the visible portion of the scanline, set the scroll, and finally turn rendering back on.
lidnariq wrote:
Less strict: You can change approximately 4 or 5 colors given one empty scanline, but the color of that blank scanline will be one of the colors you're replacing.
I think this is the way forward. If the blank scanlines are drawn with the extra backdrop colors ($3F04 one line, $3F08 the next, $3F0C after that), the seam should look clean. Then you just have to make sure 13 cycles land within the (341-256)/3 = 28-cycle horizontal blanking period, giving plenty of margin.
Code:
bit $2007 ; Skip one of the extra backdrop colors, putting pointer at a color
; The last cycle of this instruction has to land in hblank.
sta $2007 ; Write one color
stx $2007 ; Write one color
sty $2007 ; Write one color, putting pointer at next extra backdrop color
; The last cycle of this instruction has to land in hblank.
; OMITTED: wait for next scanline and load next 3 colors
tepples wrote:
Code:
bit $2007 ; Skip one of the extra backdrop colors, putting pointer at a color
; The last cycle of this instruction has to land in hblank.
sta $2007 ; Write one color
stx $2007 ; Write one color
sty $2007 ; Write one color, putting pointer at next extra backdrop color
; The last cycle of this instruction has to land in hblank.
; OMITTED: wait for next scanline and load next 3 colors
Cool idea, using the extra colors to your advantage. Also, it's a nice coincidence that each palette has 3 colors and the 6502 has 3 general purpose registers.
I was just wishing to do this to my game. The NESCraft would be split screen and when dawn would come after the night, the pallette on scanlines will change to show the sunlight effect.
tepples wrote:
Code:
bit $2007 ; Skip one of the extra backdrop colors, putting pointer at a color
; The last cycle of this instruction has to land in hblank.
sta $2007 ; Write one color
stx $2007 ; Write one color
sty $2007 ; Write one color, putting pointer at next extra backdrop color
; The last cycle of this instruction has to land in hblank.
; OMITTED: wait for next scanline and load next 3 colors
I cannot find a nice explanation for what BIT does. Does it wait for HBlank or something?
In this case, bit reads the PPU register without modifying any CPU registers. This is done to skip one color when writing to the palette.
BIT is used here only for its read' side effect (reading $2007 will increment by 1/32 the PPU address just like writes). You could just as well use any of the compare instructions for that purpose (though CPY $2007 looks a bit bizarre, we're much more used to see BIT used as reads).
Thanks for the advice and direction guys. Tepples, the way that you propose to do things fits perfect with what I'd like to do, and should create a nice clean look. Thanks again!
tokumaru wrote:
This causes a "rainbow" to be displayed on the screen, which looks like a glitch.
If this "rainbow" doesn't look too weird, can it be used as a graphical effect? Can it be manipulated where it's going to appear and can it cause other graphical glitches? Another important question is that is this effect emulated (on FCEUX for an example)?
EDIT: Also, there is something else that caught my attention: What exactly is HBlank and when does it happen?
The "rainbow" is used as a graphical effect in the "flowing palette" demo and the game
Micro Machines. I seem to remember the third-party NESRGB mod (but not the PlayChoice PPU swap mod) showing wrong colors with these programs.
Horizontal blanking (hblank) happens at the end of each scanline. On the NES, it lasts about 26 CPU cycles.
BTW another game that uses this (I think with sprite 0 for timing):
https://www.youtube.com/watch?v=geHAoWQGSfIChanges palette at the status bar, obvious glitching. Maybe turn off your sound before clicking that link though.
Tsutarja wrote:
If this "rainbow" doesn't look too weird, can it be used as a graphical effect? Can it be manipulated where it's going to appear and can it cause other graphical glitches?
It's hard to make use of it for effects because of the lack of proper CPU-PPU synchronization. Blargg's palette demos uses a pretty complex trick to get the PPU and CPU as synchronized as possible, and there's still some jitter in them. In an actual game it would be even tougher to achieve proper synchronization, and even if you tried to be consistent with the effect it would jitter by several pixels, and that usually looks like a glitch.
Quote:
Another important question is that is this effect emulated (on FCEUX for an example)?
No, not on FCEUX. But other emulators do emulate this (Nintendulator and Nestopia for sure).
Quote:
EDIT: Also, there is something else that caught my attention: What exactly is HBlank and when does it happen?
You're probably familiar with the vertical blank (VBlank), which is the time when no video is generated and the TV is supposedly moving the beam back to the upper left corner of the screen. Well, the HBlank (horizontal blank) is similar, it's the time when the TV moves the beam from the end of a scanline (on the right) to the beginning of the next (on the left). It's a much smaller period than VBlank, and there's hardly any time to do any useful PPU operations there, but raster effects are usually timed around HBlank to avoid visible glitches.
If all of this is too much hassle for you, wouldn't it make sense to use the emphasis bits in $2001 for your status bar? You would still depend on one of the palettes but it would still produce different colors.
Colour emphasis only changes the colours very slightly, unless you combine it with the monochrome bit. So if you can get away using emphasis only, you'd as well work with the normal palette restrictions. Also it wouldn't work with what the original author said (fading out playfield, while keeping status bar normal).
My $2 : In a NES game it would really shock noone to have the status bar fading out and in again when you switches screen. That's a "standard" or expected behaviour, because all games does it that way on that system. There is nothing wrong in avoiding it, but personally I wouldn't care.
What I do personally is just deal with 2 palettes that don't change through all the game for the status bar, and 2 that actually changes (the same for the sprites, also, except the constant palettes are used for the main character and item's sprites, obviously). This may sounds like a huge limitation, but in fact it isn't, or at least for the level of graphics I want to reach, that is "normal" NES graphics, not something groundbreaking that pushes the system to it's limit.
EDIT : Also some games have the status bar's colour changing depending on the level, or even sometimes changing during a level (Double Dragon II). It's actually not as noticeable as you'd think it would.