I can't run Vectorman, because inputs aren't working in the game for some reason for me. Another bug, yay.
I can't run vdpdoc.bin, because it's known to not work on hardware, and also doesn't run for me. Expects a strange 68K bus grant behavior that breaks other games and is not correct in order to run.
So that leaves me with "Shadow-Highlight Test Program #2 (PD)" as my only possible test case, and this is what I get:
First, the scrolling background on plane B on the edges of the screen are shadowed, yet in other emulators they're not.
And that ... may be the only issue? If the background were correct, the image may render correctly. But probably not.
In the docs, I noticed that Charles MacDonald got the purpose of sprite color 0x3e and 0x3f backward.
I also note that the behavior when one background plane has the priority bit set doesn't seem to actually cause the output color to become normal (not shadowed nor highlighted.)
So basically let's look at that scrolling background layer around the edges of the screen ...
Plane B contains the scrolling layer. Priority is always zero, and the color of the tiles comes out as 1 or 2 for the pattern drawn.
Plane A always has priority zero, and color zero in this area.
Sprite always has priority zero, and color zero in this area.
Per Charles MacDonald:
"Background tiles are shown at half intensity, or at normal intensity if their priority bit is set."
Per md.squee.co:
"An entry in a name table is by default shadowed with the priority bit cleared."
According to both of these, the scrolling plane B layer around the edges of the screen in this test ROM should always be shadowed, as I am rendering.
Yet in Mednafen, BlastEm, etc ... it is not.
So what am I missing?
My code, along with where I pulled notes from. This codepath is only hit when mode register 4 shadow/highlight is enabled.
Code: Select all
auto output = io.backgroundColor;
//The backdrop is shown at half intensity, while the overscan region outside
//of the display area is always shown at normal intensity.
enum : uint { Normal, Shadow, Highlight } mode = Shadow;
if(!planeB.output.priority) if(auto color = planeB.output.color) {
output = color;
//Background tiles are shown at half intensity, or at normal intensity if their priority bit is set.
mode = Shadow;
}
if(!planeA.output.priority) if(auto color = planeA.output.color) {
output = color;
mode = Shadow;
}
if(!sprite.output.priority) if(auto color = sprite.output.color) {
//Sprites with colour 15 of palette 4 will highlight the underlying pixels -
//if the underlying pixel is shadowed, it will be displayed normally.
//If it's already normal, it will be highlighted.
//** note this contradicts Charles MacDonald:
//Pixels with color 3Eh are not drawn. Instead, the underlying pixel
//(from the backdrop or background) will be shown at half intensity.
if(color == 0x3e) mode = mode == Shadow ? Normal : Highlight;
//Sprites with colour 16 of palette 4 will shadow the underlying pixels -
//if the underlying pixel is normal, it will be shadowed. If it is shadowed, nothing will occur.
//If it's highlighted, it will be displayed normally.
//** same
//Pixels with color 3Fh are not drawn. Instead, the underlying pixel
//(from the backdrop or background) will be shown at double intensity.
else if(color == 0x3f) mode = Shadow;
else {
output = color;
//Colors 0Eh, 1Eh, 2Eh, are always shown at normal intensity regardless of priority.
//I'd say this a bug rather than a feature.
mode = color == 0x0e || color == 0x1e || color == 0x2e ? Normal : Shadow;
}
}
if( planeB.output.priority) if(auto color = planeB.output.color) {
output = color;
//Background tiles are shown at half intensity, or at normal intensity if their priority bit is set.
mode = Normal;
}
if( planeA.output.priority) if(auto color = planeA.output.color) {
output = color;
mode = Normal;
}
if( sprite.output.priority) if(auto color = sprite.output.color) {
if(color == 0x3e) mode = mode == Shadow ? Normal : Highlight;
else if(color == 0x3f) mode = Shadow;
else {
output = color;
mode = Normal;
}
}
auto color = cram.read(output);
//Background tiles are shown at half intensity, or at normal intensity if their priority bit is set.
//In the latter case, this affects all other graphics elements in the region (usually 8x8) that the
//tile takes up, regardless of the tile containing opaque pixels or not.
//*** this is flawed. If we do this, shadow mode breaks on the fourth column of colors.
//if(planeB.output.priority || planeA.output.priority) mode = Normal;
//this is lazy, I know I'm cutting 50% of the color precision away, and that the actual colors are non-linear
//don't worry, when I get the demo working I'll make a proper LUT for all three modes
if(mode == Shadow ) color = (color >> 1) & 0b011011011;
if(mode == Highlight) color = (color << 1) & 0b110110110;
outputPixel(color);
}