Fix Bug when rendering overlapping HD sprites with different background priority (SourMesen/Mesen issue 609)

Fix Bug when rendering overlapping HD sprites with different background priority (SourMesen/Mesen issue 609)
This commit is contained in:
mkwong98 2020-11-01 20:29:12 +08:00
parent c48e6285ee
commit 8761918a46
2 changed files with 111 additions and 11 deletions

View file

@ -13,6 +13,7 @@ HdNesPack::HdNesPack(shared_ptr<HdPackData> hdData, EmulationSettings* settings)
{
_hdData = hdData;
_settings = settings;
spriteMask.resize(hdData->Scale * hdData->Scale);
}
HdNesPack::~HdNesPack()
@ -50,6 +51,29 @@ void HdNesPack::DrawColor(uint32_t color, uint32_t *outputBuffer, uint32_t scale
}
}
void HdNesPack::DrawSpriteColor(uint32_t color, uint32_t* outputBuffer, uint32_t scale, uint32_t screenWidth, int spriteID)
{
if (scale == 1 && spriteID <= spriteMask[0]) {
*outputBuffer = color;
spriteMask[0] = spriteID;
}
else {
for (uint32_t y = 0; y < scale; y++) {
for (uint32_t x = 0; x < scale; x++) {
vector<int>::iterator it = spriteMask.begin();
if (spriteID <= *it) {
*it = spriteID;
* outputBuffer = color;
}
it++;
outputBuffer++;
}
outputBuffer += screenWidth - scale;
}
}
}
void HdNesPack::DrawCustomBackground(HdBackgroundInfo& bgInfo, uint32_t *outputBuffer, uint32_t x, uint32_t y, uint32_t scale, uint32_t screenWidth)
{
int brightness = bgInfo.Brightness;
@ -140,6 +164,80 @@ void HdNesPack::DrawTile(HdPpuTileInfo &tileInfo, HdPackTileInfo &hdPackTileInfo
}
}
void HdNesPack::DrawSpriteTile(HdPpuTileInfo& tileInfo, HdPackTileInfo& hdPackTileInfo, uint32_t* outputBuffer, uint32_t screenWidth, int spriteID)
{
if (hdPackTileInfo.IsFullyTransparent) {
return;
}
uint32_t scale = GetScale();
uint32_t* bitmapData = hdPackTileInfo.HdTileData.data();
uint32_t tileWidth = 8 * scale;
uint8_t tileOffsetX = tileInfo.HorizontalMirroring ? 7 - tileInfo.OffsetX : tileInfo.OffsetX;
uint32_t bitmapOffset = (tileInfo.OffsetY * scale) * tileWidth + tileOffsetX * scale;
int32_t bitmapSmallInc = 1;
int32_t bitmapLargeInc = tileWidth - scale;
if (tileInfo.HorizontalMirroring) {
bitmapOffset += scale - 1;
bitmapSmallInc = -1;
bitmapLargeInc = tileWidth + scale;
}
if (tileInfo.VerticalMirroring) {
bitmapOffset += tileWidth * (scale - 1);
bitmapLargeInc = (tileInfo.HorizontalMirroring ? (int32_t)scale : -(int32_t)scale) - (int32_t)tileWidth;
}
uint32_t rgbValue;
vector<int>::iterator it = spriteMask.begin();
if (hdPackTileInfo.HasTransparentPixels || hdPackTileInfo.Brightness != 255) {
for (uint32_t y = 0; y < scale; y++) {
for (uint32_t x = 0; x < scale; x++) {
if (spriteID <= *it) {
if (hdPackTileInfo.Brightness == 255) {
rgbValue = *(bitmapData + bitmapOffset);
}
else {
rgbValue = AdjustBrightness((uint8_t*)(bitmapData + bitmapOffset), hdPackTileInfo.Brightness);
}
if (!hdPackTileInfo.HasTransparentPixels || (bitmapData[bitmapOffset] & 0xFF000000) == 0xFF000000) {
*outputBuffer = rgbValue;
*it = spriteID;
}
else {
if (bitmapData[bitmapOffset] & 0xFF000000) {
BlendColors((uint8_t*)outputBuffer, (uint8_t*)& rgbValue);
}
}
}
it++;
outputBuffer++;
bitmapOffset += bitmapSmallInc;
}
bitmapOffset += bitmapLargeInc;
outputBuffer += screenWidth - scale;
}
}
else {
for (uint32_t y = 0; y < scale; y++) {
for (uint32_t x = 0; x < scale; x++) {
if (spriteID <= *it) {
*it = spriteID;
*outputBuffer = *(bitmapData + bitmapOffset);
}
it++;
outputBuffer++;
bitmapOffset += bitmapSmallInc;
}
bitmapOffset += bitmapLargeInc;
outputBuffer += screenWidth - scale;
}
}
}
uint32_t HdNesPack::GetScale()
{
return _hdData->Scale;
@ -284,7 +382,9 @@ void HdNesPack::GetPixels(uint32_t x, uint32_t y, HdPpuPixelInfo &pixelInfo, uin
hdPackTileInfo = GetCachedMatchingTile(x, y, &pixelInfo.Tile);
}
int lowestBgSprite = 999;
//init bg sprite depth mask
for (int i = 0; i < spriteMask.size(); i++) spriteMask[i] = 999;
DrawColor(_palette[pixelInfo.Tile.PpuBackgroundColor], outputBuffer, _hdData->Scale, screenWidth);
@ -295,15 +395,11 @@ void HdNesPack::GetPixels(uint32_t x, uint32_t y, HdPpuPixelInfo &pixelInfo, uin
if(hasSprite) {
for(int k = pixelInfo.SpriteCount - 1; k >= 0; k--) {
if(pixelInfo.Sprite[k].BackgroundPriority) {
if(pixelInfo.Sprite[k].SpriteColorIndex != 0) {
lowestBgSprite = k;
}
hdPackSpriteInfo = GetMatchingTile(x, y, &pixelInfo.Sprite[k]);
if(hdPackSpriteInfo) {
DrawTile(pixelInfo.Sprite[k], *hdPackSpriteInfo, outputBuffer, screenWidth);
DrawSpriteTile(pixelInfo.Sprite[k], *hdPackSpriteInfo, outputBuffer, screenWidth, k);
} else if(pixelInfo.Sprite[k].SpriteColorIndex != 0) {
DrawColor(_palette[pixelInfo.Sprite[k].SpriteColor], outputBuffer, _hdData->Scale, screenWidth);
DrawSpriteColor(_palette[pixelInfo.Sprite[k].SpriteColor], outputBuffer, _hdData->Scale, screenWidth, k);
}
}
}
@ -328,12 +424,12 @@ void HdNesPack::GetPixels(uint32_t x, uint32_t y, HdPpuPixelInfo &pixelInfo, uin
if(hasSprite) {
for(int k = pixelInfo.SpriteCount - 1; k >= 0; k--) {
if(!pixelInfo.Sprite[k].BackgroundPriority && lowestBgSprite > k) {
if(!pixelInfo.Sprite[k].BackgroundPriority) {
hdPackSpriteInfo = GetMatchingTile(x, y, &pixelInfo.Sprite[k]);
if(hdPackSpriteInfo) {
DrawTile(pixelInfo.Sprite[k], *hdPackSpriteInfo, outputBuffer, screenWidth);
DrawSpriteTile(pixelInfo.Sprite[k], *hdPackSpriteInfo, outputBuffer, screenWidth, k);
} else if(pixelInfo.Sprite[k].SpriteColorIndex != 0) {
DrawColor(_palette[pixelInfo.Sprite[k].SpriteColor], outputBuffer, _hdData->Scale, screenWidth);
DrawSpriteColor(_palette[pixelInfo.Sprite[k].SpriteColor], outputBuffer, _hdData->Scale, screenWidth, k);
}
}
}

View file

@ -35,11 +35,15 @@ private:
bool _useCachedTile = false;
int32_t _scrollX = 0;
vector<int> spriteMask;
__forceinline void BlendColors(uint8_t output[4], uint8_t input[4]);
__forceinline uint32_t AdjustBrightness(uint8_t input[4], int brightness);
__forceinline void DrawColor(uint32_t color, uint32_t* outputBuffer, uint32_t scale, uint32_t screenWidth);
__forceinline void DrawTile(HdPpuTileInfo &tileInfo, HdPackTileInfo &hdPackTileInfo, uint32_t* outputBuffer, uint32_t screenWidth);
__forceinline void DrawSpriteTile(HdPpuTileInfo& tileInfo, HdPackTileInfo& hdPackTileInfo, uint32_t* outputBuffer, uint32_t screenWidth, int spriteID);
__forceinline void DrawSpriteColor(uint32_t color, uint32_t* outputBuffer, uint32_t scale, uint32_t screenWidth, int spriteID);
__forceinline HdPackTileInfo* GetCachedMatchingTile(uint32_t x, uint32_t y, HdPpuTileInfo* tile);
__forceinline HdPackTileInfo* GetMatchingTile(uint32_t x, uint32_t y, HdPpuTileInfo* tile, bool* disableCache = nullptr);