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:
parent
c48e6285ee
commit
8761918a46
2 changed files with 111 additions and 11 deletions
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -35,10 +35,14 @@ 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);
|
||||
|
|
Loading…
Add table
Reference in a new issue