Sprite Priorities (Again...)

This is an archive of a topic from NESdev BBS, taken in mid-October 2019 before a server upgrade.
View original topic
Sprite Priorities (Again...)
by on (#4690)
If Sprite 5 and Sprite 20 are drawn in exactly the same place, with 5 behind the bg and 20 in front, and all of Sprite 5's pixels are transparent then does sprite 20 get drawn?

In other words if a pixel is transparent then does it count as having a higher priority?

The reason that I am asking this is because in Castlevania I know that when you enter the castle you are supposed to enter it through the door using the afformentioned method. BUT it does not seem to work.

If I do it so that a pixel takes priority whether it is transparent or not then Castlevania seems to work, but other games then seem to suffer. I am very confused...

by on (#4692)
Transparent pixels are ignored when determining relative sprite priority - in this case, you will see sprite #20.

by on (#4696)
You'll see sprite BG, then sprite 5, then sprite 20. If sprite 5 is transparent, if makes no effect, but if it is black, then you see sprite 5 behind the BG, then sprite 20 isn't visible because it has a black pixel from sprite 5 above it, this one isn't visible for the player because the BG transparent color is also black.

by on (#4702)
So how does Castlevania make the main character enter the door and go behind the wall when you enter the castle? I have checked and the character remains a fg sprite and there is also a background sprite that is fully transparent which it is supposed to hide behind. If transparency does not affect the priority of a pixel then how do they manage it?

by on (#4706)
The sprite is not transparent - it is simply the same color as the background. The actual colors are irrelevant; the PPU does not determine the actual color to display until AFTER it has determined which sprite to draw.

by on (#4710)
If the sprite is the same colour as the background, then surely it would be totally transparent and therefore have no priority?

by on (#4713)
Argggh! The PPU is color-blind up until the last moment; it only sees palette indicies when composing graphics. All that's relevant for transparency is whether the two low bits of the palette index are zero (the two bits specified in CHR data, as opposed to the higher bits specified by the attributes or whether it's BG/OBJ sub-palette). It's not like the "chroma key" on TV where they have a blue/green screen behind and anything approximately matching that color is transparent to the underlay.

by on (#4722)
In other words, the sprite isn't transparent, it's black, and the BG is also black so the sprite is invisible, while not techically transparant.

by on (#4723)
Bregalad wrote:
...so the sprite is invisible, while not techically transparant.


So... What's the difference between the two?

by on (#4724)
Color 0... and ONLY color 0 is transparent ($3Fx0, $3Fx4, $3Fx8, $3FxC). If the sprite is to draw any color other than those colors the pixel is NOT TRANSPARENT. Whether or not the drawn pixel will be indistinguishable from the background to the user... the NES doesn't care.

So if the game has a black background and a fully black sprite on top of it... a human won't be able to tell where the sprite is by looking at the screen (since the same color is being drawn everywhere) -- but that doesn't necessarily make the sprite transparent. It just makes it blend in.


So agian... the only thing that matters when determining whether or not a sprite/bg pixel is transparent is if both the CHR bits are 0. Attribute bits don't matter.. the palette doesn't matter... nothing else matters. If the bg/spr is outputting color 0, it's transparent, if it's outputting color 1-3, it's opaque.

by on (#4725)
Transparency is defined by (0x3F00). So if 0x3F02 has the same value as 0x3F00, is 0x3F02 transparent?

I understand what you say about the human eye not being able to see the sprite if it is that same colour as the bg but please try Castlevania and you will see what I mean. Using priorities, they make the main character dissapear when he enters the door.

Also is 0x3F00 mirrored to 0x3F04, 0x3F08, 0x3F0C, 0x3F10, 0x3F14, 0x3F18, 0x3F1C?

by on (#4726)
WedNESday wrote:
Transparency is defined by (0x3F00). So if 0x3F02 has the same value as 0x3F00, is 0x3F02 transparent?

No.

Quote:
Also is 0x3F00 mirrored to 0x3F04, 0x3F08, 0x3F0C, 0x3F10, 0x3F14, 0x3F18, 0x3F1C?

Yes.

by on (#4727)
Argh!!!!!!!

Then in that case, can somebody please explain palettes to me in a post. Please don't refer me to any txt files, I have read them all. Leave no detail out...

by on (#4728)
The color written at $3f00, that is mirrored to $3f04, $3f08, $3f0c, $3f10, $3f14, $3f18 and $3f1c, is the transparent color. Only writes to $3f00 and $3f10 are taken care (so a write, for example to $3f1c, is without effect).

After all the priority calculations, the color drawn of the screen can be from a sprite image (that has high priority, or that have low priority and is behind a transparent BG pixel), or from a bg image (if there is no sprite, if there is a sprite with lower priority that is behind a non-transparent BG pixel, etc...), if no pixel has to be shown from BG nor sprites, the transparent color will be there.

The value of the color themselves have nothing to do with the priorities or transparent pixels.

by on (#4729)
Bregalad wrote:
Quote:
Also is 0x3F00 mirrored to 0x3F04, 0x3F08, 0x3F0C, 0x3F10, 0x3F14, 0x3F18, 0x3F1C?

Yes.


Actually... no.


Here's the deal:

$3F10 mirrors $3F00
$3F14 mirrors $3F04
$3F18 mirrors $3F08
$3F1C mirrors $3F0C

$3F20-$3FFF mirrors $3F00-$3F1F


$3F00/$3F04/$3F08/$3F0C are NEVER DRAWN as part of a BG/sprite. Never never never never... since they are the 'color 0' value of the graphic (though they all exist, and can be used for the BG color when rendering is disabled). $3F00 holds the "background color" which is drawn if BOTH BG/Sprite pixels are transparent. (Note that $3F00 is the bg color only if rendering is enabled -- if rendering is disabled [both bg and sprites disabled] then it is possible for the game to use any palette entry as the bg color)

logic flows kind of like this (note: only true when rendering enabled) :

Code:
if sprite pixel is not transparent
 -> if sprite pixel has foreground priority, render it
 -> otherwise if background pixel is not transparent, render it
 -> otherwise render sprite pixel
else (sprite pixel is transparent)
 -> if background pixel is not transparent, render it
 -> otherwise (both are transparent), render color at ppu$3F00


For areas of the screen where there is no existing sprite -- the sprite pixel is transparent. If sprites are disabled, or if the sprite pixel is in the left 8 pixels of the screen and sprite clipping is turned on... the sprite pixel is transparent. Otherwise transparency is determined by CHR bits of the sprites graphic: 0=transparent... 1,2,3=opaque. If the BG is disabled or in the clipped range (left 8 pixels of the screen when clipping enabled), the BG pixel is transparent -- otherwise BG transparency depends on the BG graphics CHR bits -- same as sprites.

Attribute bits and palette lookup do not come into play at all until AFTER it's determined which pixel will be displayed.

by on (#4732)
Quote:
The color written at $3f00, that is mirrored to $3f04, $3f08, $3f0c, $3f10, $3f14, $3f18 and $3f1c, is the transparent color. Only writes to $3f00 and $3f10 are taken care (so a write, for example to $3f1c, is without effect).


This is what is confusing people; the values in the palette at $3f00 are irrelevant for the determination of transparency. Transparency isn't about what you see on the screen (though what you see might match it); it's about what is considered opaque and what is considered transparent.

Like I said before, all that matters are low two bits of the palette index of the pixel, as specified by the CHR (tile) data. CHR data specifies only the low two bits of the palette index. If all you had was the CHR data for a given background and sprites, if you didn't know the palette or the attribute bits, you could still determine which pixels of the background and sprites will make it to the screen.

It's not about ROY G BIV! :)

by on (#4804)
blargg wrote:
Quote:
It's not about ROY G BIV! :)


Eh???

OK thanks to you guys and now have correct sprite transparency effect, but there is one more thing bothering me. If a sprite's pixel is 0 then it has no priority, but if it is 1-3 then it has priority. Is this correct? Also Sprite 0 has a higher priority then Sprite 63?

What I am having trouble with is Castlevania, when you enter the castle you are supposed to disappear like Mario does when he goes down a pipe, but for some unknown reason you do not disappear.

by on (#4805)
You must track the visible sprites, the drawed sprites. Go from 0 to 3Fh - a solid sprite is pattern AND 3. If true, check the priority bit - for LOW priority, you allow a new sprite pixel only if there's no pixel (sprite OR background at current location); else, if HIGH priority, you draw it.

Code:
                  64 SPRITES
SPRITE #0 ------------------------- SPRITE #3F
 HIGH PRIORITY -------------- LOW PRIORITY


Amem. ^_^;;

by on (#4808)
WedNESday wrote:
f a sprite's pixel is 0 then it has no priority, but if it is 1-3 then it has priority. Is this correct?


A pattern value of 0 is transparent... so I guess you could say it has no priority. So yes @ this... even though it's kind of worded weird.

Quote:
Also Sprite 0 has a higher priority then Sprite 63?

Yes. Sprite 0 is always drawn 'on top' of all the other sprites. Sprite 63 is always drawn below the other sprites.

As for your Castlevania problems... I don't really know what the game is doing to pull off its effect... so I can't really help you much more than explaining the general workings.

Probably what the game is doing is putting an opaque sprite with background priority right where the game wants simon to disappear. Simon likely has foreground priority, but a HIGHER sprite number (indicating he has lower priority than the sprite which is there to "hide" him).

What will happen is... sprite priorities are calculated first ... so that when Simon and the Hide sprite overlap... the NES will look at them and see the Hide sprite has a higher priority than Simon... so it will take the Hide sprite's pixels and compare those to the BG. Since the Hide sprite has background priority, the BG wins and gets displayed to the screen.

What you might be doing... is you might be letting Simon win the priority fight because he has foreground priority... even though he has a higher sprite number than the Hide sprite.

That's just a guess though.... like I said I don't really know what trick CV is pulling.

by on (#4824)
See if this concise summary helps.

A transparent pixel is one for which the lowest two bits of the palette index are clear (index AND 3 = 0). For each pixel on screen, do the following:

- Scan through the first 8 sprites that intersect the pixel, starting at sprite 0 (there may be fewer than 8 that intersect a given pixel, of course). Stop on the first sprite whose pixel is non-transparent. The result of this is either nothing, or a single non-transparent sprite pixel. The sprites are not scanned any further.

- If a non-transparent sprite pixel was found and either a) the sprite is in front of the background (bit 5 of attributes is clear), or b) the background pixel is transparent, then draw the sprite's pixel.

- If a sprite pixel wasn't drawn and the background pixel is non-transparent, draw the background pixel.

- If neither sprite nor background pixel were drawn, then draw pixel as palette index 0.

by on (#4833)
Thanks everyone, now I have it sorted (it was my own fault lol)...

by on (#4837)
Quote:
You must track the visible sprites, the drawed sprites. Go from 0 to 3Fh - a solid sprite is pattern AND 3. If true, check the priority bit - for LOW priority, you allow a new sprite pixel only if there's no pixel (sprite OR background at current location); else, if HIGH priority, you draw it.


Maybe i missunderstood something fx3, but you are advicing him to go from sprite 0 to 63?
If it is that the case the emulation will not be ok.
Sprites have temporary memories that only can hold 8 sprites and 2002.5
is set if its found one more and the other are not drawn on the screen (thats becouse a real nes show flickering whem 8+ sprites are in the same scanline).

WedNESDay: i dont know if your engine is pixel by pixel or whatever, but you should limit the sprites that are visible.
Trying to draw all 64 sprites will give (of course) a better sprite image on screen (no flickering) but will not behave like a real NES.

fx3: as i said if i missunderstood something take it if i had say nothing. :)

by on (#4843)
Quote:
Trying to draw all 64 sprites will give (of course) a better sprite image on screen (no flickering) but will not behave like a real NES.


Remember, the NES sprites do not inherently flicker; all flicker is done intentionally in software (as an alternative to having some (portions of) sprites just disappear). Also, not emulating the limit of 8 sprites per scanline enhances some games, but causes graphical errors on others which use some sprites to mask others (you could allow the user to choose which they want).

by on (#4849)
Thanks for all of the replies but I have managed to solve the problem now.

Btw, WedNESday draws the screen on a scanline for scanline basis.

by on (#4866)
Anes wrote:
Maybe i missunderstood something fx3, but you are advicing him to go from sprite 0 to 63?
If it is that the case the emulation will not be ok.
Sprites have temporary memories that only can hold 8 sprites and 2002.5
is set if its found one more and the other are not drawn on the screen (thats becouse a real nes show flickering whem 8+ sprites are in the same scanline).


Supposely, you evaluate ALL the sprites at clock cycle 256. ^_^;;
Yes, there's a 8-sprites buffer, indeed, which follows the same rule for priority.

by on (#4867)
Fx3 wrote:
Supposely, you evaluate ALL the sprites at clock cycle 256. ^_^;;
Yes, there's a 8-sprites buffer, indeed, which follows the same rule for priority.


No you don't, but that's how most emulators do it. If you want to do it 100% correctly, you evaluate them while the scanline is rendered using a procedure I described in a topic somewhere around here...

by on (#4879)
Are there any NES programs who behave differently depending on which of those two methos is used to emulate the PPU?

by on (#4887)
Quote:
Fx3 escribió:
Supposely, you evaluate ALL the sprites at clock cycle 256. ^_^;;
Yes, there's a 8-sprites buffer, indeed, which follows the same rule for priority.
Quote:
No you don't, but that's how most emulators do it. If you want to do it 100% correctly, you evaluate them while the scanline is rendered using a procedure I described in a topic somewhere around here...



Thats right if you read brad doc it says that sprites are evaluated during scanline render wich gives you 256cc / 64sprites: 4cc takes each evaluation. so you should have a counter that when 4 cc pass evaluate sprites 0.. etc. Which i really dont know if scanline cc 0 evaluates first i mean:

Code:

static BYTE cc = 0;

 if (cc_sprites == 0)
   //Check Sprite In Rage and test how many
   cc = 3;
 else
   cc--;



OR

Code:

static BYTE cc = 0
 if (cc_sprites == 3)
   //Check Sprite In Rage and test how many
   cc = 0;
 else
   cc++;



Checking all 64 sprites in a sinlge cc, is not accuratest at al (maybe some games uses it WedNESDay) and if you keep checking after a 8+ has been found its a waste of time to your emulator, you should stop checking when sprite 7 (0 - 7) is in range and reset you "csprites in ranges" var.

I really dont know if games take adventage of it, but the only thing i know is that when i uses the method i explained above, battletoads didnt hang and when i use the "one cc check all sprites" battletoads started to hang (altmost for me).

by on (#4888)
WedNESday draws the screen (and has no issues with priority or anything else) by drawing the scanline and then going back and drawing the sprites on a pixel for pixel basis. When it has found 8 sprites it then stops. So far this method is very simple and proves very accurate.

by on (#4889)
Quote:
WedNESday draws the screen on a scanline for scanline basis.

mmm... scanline rendering (if you are rendering optimized) will give you a liittle more speed in the emulator, but it will not be accurate, there are some programs or games that do H split effects and you will not detect that.
Another thing is cc calc, its a little more complicated when its by scanline.

I suggest you change by pixel. I ussed scanline basis in my emulator dev beggining and i gave a lot of problems regarding cycles calc and those things.

Sprite 0 hit is another issue can you detect exactly when its hited.

And remember that a scanline is 341/3 cpu cc not 256 ppu cc.
256 is for rendering the playfield and the other falls in hblank.

by on (#4891)
WedNESday can do both vertical and horizontal scrolling including split screen scrolling no problem. Also, WedNESday ignores the PPU documents (341 ppu cc etc.) and just renders the scanline normally (i.e. it just fetches 1 tile every 8 pixels and renders it). I know that some of you may think that this would make the emulator run incorrectly but most (90%) NROM games (no mapper support yet) run perfectly (still some PPU work to do).

by on (#4892)
He means you'll have issues with games which do mid-scanline effects like Final Fantasy, Marble Madness, Micro Machines, and several others.

Rounding off when Sprite-0 hit happens could affect games as well... if you're rounding off to the start or end of the scanline which sprite 0 hit happens, several games will have display problems.

by on (#4893)
I am currently emulating accurate CPU timing so that may help. What kind of effect does Final Fantasy etc. use that may effect my emulator?

by on (#4894)
When you light up an orb in Final Fantasy, the game does timed code to create a "beam of light" which makes sort of a slanted rectangled from the top-left corner of the screen to the player's position. The game accomplishes this by toggling monochrome mode at certain points in the scanline. With a typical scanline renderer... you will either not show this effect at all... or you will show every scanline in monochrome mode.

Marble Madness swaps CHR midscanline for the race titles. If you remember playing this game in NESticle back in the day, you know how a scanline renderer will display it (shows garbage tiles where there should be text).

Micro Machines does VERY weird things in the title screen... relying on the PPU address to be incremented at a very specific time. The specific glitch I have in mind is minor and hard to explain... but it's still worth mentioning.

by on (#4897)
Thanks for letting me know. For the time being i'll stick with my scanline engine, just so I can play some of the more basic ROMs. But in the future I will write an accurate PPU renderer. The real point that I am making is that I never intended to make my NES emulator 100% accurate, I just did it for fun, like most people.

by on (#4902)
Quote:
The real point that I am making is that I never intended to make my NES emulator 100% accurate, I just did it for fun, like most people


I think doing it for fun doest mean that an emulator should display only a window with a title saying "my emulator" or if you are progamming in a console OS says "my emulator" and exits, you should be the more accurate you need, i do it for fun too, but some games that i owned when i was child doesnt work and that becouse accuracy, so i try to fix it.

The point is there is nothing to "fun" do with "accuracy".

P.D= or isnt FUNNY to do it ACCURATTLY?