diff --git a/Core/HdBuilderPpu.h b/Core/HdBuilderPpu.h index 1b1a67ea..f8149cd0 100644 --- a/Core/HdBuilderPpu.h +++ b/Core/HdBuilderPpu.h @@ -25,6 +25,10 @@ protected: _lastSprite = nullptr; uint32_t color = GetPixelColor(); _currentOutputBuffer[(_scanline << 8) + _cycle - 1] = _paletteRAM[color & 0x03 ? color : 0]; + uint32_t backgroundColor = 0; + if(_flags.BackgroundEnabled && _cycle > _minimumDrawBgCycle) { + backgroundColor = (((_state.LowBitShift << _state.XScroll) & 0x8000) >> 15) | (((_state.HighBitShift << _state.XScroll) & 0x8000) >> 14); + } if(_needChrHash) { uint16_t addr = 0; @@ -41,7 +45,17 @@ protected: _needChrHash = false; } + bool hasBgSprite = false; if(_lastSprite && _flags.SpritesEnabled) { + if(backgroundColor == 0) { + for(uint8_t i = 0; i < _spriteCount; i++) { + if(_spriteTiles[i].BackgroundPriority) { + hasBgSprite = true; + break; + } + } + } + if(_lastSprite->AbsoluteTileAddr >= 0) { sprite.TileIndex = (_isChrRam ? (_lastSprite->TileAddr & _chrRamIndexMask) : _lastSprite->AbsoluteTileAddr) / 16; sprite.PaletteColors = ReadPaletteRAM(_lastSprite->PaletteOffset + 3) | (ReadPaletteRAM(_lastSprite->PaletteOffset + 2) << 8) | (ReadPaletteRAM(_lastSprite->PaletteOffset + 1) << 16) | 0xFF000000; @@ -50,7 +64,7 @@ protected: sprite.TileData[i] = _mapper->GetMemoryValue(DebugMemoryType::ChrRom, _lastSprite->AbsoluteTileAddr / 16 * 16 + i); } - _hdPackBuilder->ProcessTile(_cycle - 1, _scanline, _lastSprite->AbsoluteTileAddr, sprite, _mapper, false, _bankHashes[_lastSprite->TileAddr / _chrRamBankSize]); + _hdPackBuilder->ProcessTile(_cycle - 1, _scanline, _lastSprite->AbsoluteTileAddr, sprite, _mapper, false, _bankHashes[_lastSprite->TileAddr / _chrRamBankSize], false); } } @@ -64,7 +78,7 @@ protected: tile.TileData[i] = _mapper->GetMemoryValue(DebugMemoryType::ChrRom, lastTile->AbsoluteTileAddr / 16 * 16 + i); } - _hdPackBuilder->ProcessTile(_cycle - 1, _scanline, lastTile->AbsoluteTileAddr, tile, _mapper, false, _bankHashes[lastTile->TileAddr / _chrRamBankSize]); + _hdPackBuilder->ProcessTile(_cycle - 1, _scanline, lastTile->AbsoluteTileAddr, tile, _mapper, false, _bankHashes[lastTile->TileAddr / _chrRamBankSize], hasBgSprite); } } } else { diff --git a/Core/HdData.h b/Core/HdData.h index b8aedc99..87e064cf 100644 --- a/Core/HdData.h +++ b/Core/HdData.h @@ -226,6 +226,7 @@ struct HdPackTileInfo : public HdTileKey bool DefaultTile; bool Blank; bool HasTransparentPixels; + bool TransparencyRequired; bool IsFullyTransparent; vector HdTileData; uint32_t ChrBankId; @@ -252,7 +253,7 @@ struct HdPackTileInfo : public HdTileKey for(uint8_t j = 0; j < 8; j++) { uint8_t color = ((lowByte >> (7 - j)) & 0x01) | (((highByte >> (7 - j)) & 0x01) << 1); uint32_t rgbColor; - if(IsSpriteTile()) { + if(IsSpriteTile() || TransparencyRequired) { rgbColor = color == 0 ? 0x00FFFFFF : palette[(PaletteColors >> ((3 - color) * 8)) & 0x3F]; } else { rgbColor = palette[(PaletteColors >> ((3 - color) * 8)) & 0x3F]; diff --git a/Core/HdNesPack.cpp b/Core/HdNesPack.cpp index 4dbcf489..1b5ed114 100644 --- a/Core/HdNesPack.cpp +++ b/Core/HdNesPack.cpp @@ -64,22 +64,14 @@ void HdNesPack::DrawCustomBackground(uint32_t *outputBuffer, uint32_t x, uint32_ } } -bool HdNesPack::DrawTile(HdPpuTileInfo &tileInfo, HdPackTileInfo &hdPackTileInfo, uint32_t *outputBuffer, uint32_t screenWidth, bool drawBackground) +void HdNesPack::DrawTile(HdPpuTileInfo &tileInfo, HdPackTileInfo &hdPackTileInfo, uint32_t *outputBuffer, uint32_t screenWidth) { - if(tileInfo.BackgroundPriority && tileInfo.BgColorIndex != 0) { - //Nothing to draw, tile is hidden - return false; + if(hdPackTileInfo.IsFullyTransparent) { + return; } uint32_t bgColor = _palette[tileInfo.PpuBackgroundColor]; uint32_t scale = GetScale(); - if(hdPackTileInfo.IsFullyTransparent) { - if(drawBackground) { - DrawColor(bgColor, outputBuffer, scale, screenWidth); - } - return false; - } - uint32_t *bitmapData = hdPackTileInfo.HdTileData.data(); uint32_t tileWidth = 8 * scale; uint8_t tileOffsetX = tileInfo.HorizontalMirroring ? 7 - tileInfo.OffsetX : tileInfo.OffsetX; @@ -96,7 +88,6 @@ bool HdNesPack::DrawTile(HdPpuTileInfo &tileInfo, HdPackTileInfo &hdPackTileInfo bitmapLargeInc = (tileInfo.HorizontalMirroring ? (int32_t)scale : -(int32_t)scale) - (int32_t)tileWidth; } - bool pixelDrawn = false; uint32_t rgbValue; if(hdPackTileInfo.HasTransparentPixels || hdPackTileInfo.Brightness < 255) { for(uint32_t y = 0; y < scale; y++) { @@ -109,14 +100,9 @@ bool HdNesPack::DrawTile(HdPpuTileInfo &tileInfo, HdPackTileInfo &hdPackTileInfo if(!hdPackTileInfo.HasTransparentPixels || (bitmapData[bitmapOffset] & 0xFF000000) == 0xFF000000) { *outputBuffer = rgbValue; - pixelDrawn = true; } else { - if(drawBackground) { - *outputBuffer = bgColor; - } if(bitmapData[bitmapOffset] & 0xFF000000) { BlendColors((uint8_t*)outputBuffer, (uint8_t*)&rgbValue); - pixelDrawn = true; } } outputBuffer++; @@ -135,10 +121,7 @@ bool HdNesPack::DrawTile(HdPpuTileInfo &tileInfo, HdPackTileInfo &hdPackTileInfo bitmapOffset += bitmapLargeInc; outputBuffer += screenWidth - scale; } - pixelDrawn = true; } - - return pixelDrawn; } uint32_t HdNesPack::GetScale() @@ -210,7 +193,15 @@ bool HdNesPack::IsNextToSprite(HdPpuPixelInfo *screenTiles, uint32_t x, uint32_t } }; for(int i = -1; i <= 1; i++) { + if(y + i < 0 || y + i >= PPU::ScreenHeight) { + continue; + } + for(int j = -1; j <= 1; j++) { + if(x + j < 0 || x + j >= PPU::ScreenWidth) { + continue; + } + if(!hasNonBackgroundSurrounding) { processAdjacentTile(screenTiles[(i + y) * 256 + j + x]); } @@ -244,21 +235,20 @@ void HdNesPack::GetPixels(HdPpuPixelInfo *screenTiles, uint32_t x, uint32_t y, H bool hasBgSprite = false; int lowestBgSprite = 999; - bool needBg = true; + + DrawColor(_palette[pixelInfo.Tile.PpuBackgroundColor], outputBuffer, hdData->Scale, screenWidth); + if(hasSprite) { for(int k = pixelInfo.SpriteCount - 1; k >= 0; k--) { if(pixelInfo.Sprite[k].BackgroundPriority) { hasBgSprite = true; lowestBgSprite = k; - if(pixelInfo.Tile.BgColorIndex == 0) { - hdPackSpriteInfo = GetMatchingTile(screenTiles, x, y, pixelInfo.Sprite[k]); - if(hdPackSpriteInfo) { - needBg &= !DrawTile(pixelInfo.Sprite[k], *hdPackSpriteInfo, outputBuffer, screenWidth, needBg); - } else if(pixelInfo.Sprite[k].SpriteColorIndex != 0) { - DrawColor(_palette[pixelInfo.Sprite[k].SpriteColor], outputBuffer, hdData->Scale, screenWidth); - needBg = false; - } + hdPackSpriteInfo = GetMatchingTile(screenTiles, x, y, pixelInfo.Sprite[k]); + if(hdPackSpriteInfo) { + DrawTile(pixelInfo.Sprite[k], *hdPackSpriteInfo, outputBuffer, screenWidth); + } else if(pixelInfo.Sprite[k].SpriteColorIndex != 0) { + DrawColor(_palette[pixelInfo.Sprite[k].SpriteColor], outputBuffer, hdData->Scale, screenWidth); } } } @@ -270,18 +260,15 @@ void HdNesPack::GetPixels(HdPpuPixelInfo *screenTiles, uint32_t x, uint32_t y, H DrawCustomBackground(outputBuffer, x, y, hdData->Scale, screenWidth); } - bool drawBg = !hasBgSprite || pixelInfo.Tile.BgColorIndex != 0 || needBg; - if(drawBg) { - if(hdPackTileInfo) { - DrawTile(pixelInfo.Tile, *hdPackTileInfo, outputBuffer, screenWidth, true); - } else { - //Draw regular SD background tile - bool useCustomBackground = !hasNonBackgroundSurrounding && hasCustomBackground && pixelInfo.Tile.BgColorIndex == 0; - if(useCustomBackground) { - DrawCustomBackground(outputBuffer, x, y, hdData->Scale, screenWidth); - } else { - DrawColor(_palette[pixelInfo.Tile.BgColor], outputBuffer, hdData->Scale, screenWidth); - } + if(hdPackTileInfo) { + DrawTile(pixelInfo.Tile, *hdPackTileInfo, outputBuffer, screenWidth); + } else { + //Draw regular SD background tile + bool useCustomBackground = !hasNonBackgroundSurrounding && hasCustomBackground && pixelInfo.Tile.BgColorIndex == 0; + if(useCustomBackground) { + DrawCustomBackground(outputBuffer, x, y, hdData->Scale, screenWidth); + } else if(pixelInfo.Tile.BgColorIndex != 0 || hasNonBackgroundSurrounding) { + DrawColor(_palette[pixelInfo.Tile.BgColor], outputBuffer, hdData->Scale, screenWidth); } } @@ -290,7 +277,7 @@ void HdNesPack::GetPixels(HdPpuPixelInfo *screenTiles, uint32_t x, uint32_t y, H if(!pixelInfo.Sprite[k].BackgroundPriority && lowestBgSprite > k) { hdPackSpriteInfo = GetMatchingTile(screenTiles, x, y, pixelInfo.Sprite[k]); if(hdPackSpriteInfo) { - DrawTile(pixelInfo.Sprite[k], *hdPackSpriteInfo, outputBuffer, screenWidth, false); + DrawTile(pixelInfo.Sprite[k], *hdPackSpriteInfo, outputBuffer, screenWidth); } else if(pixelInfo.Sprite[k].SpriteColorIndex != 0) { DrawColor(_palette[pixelInfo.Sprite[k].SpriteColor], outputBuffer, hdData->Scale, screenWidth); } diff --git a/Core/HdNesPack.h b/Core/HdNesPack.h index 153aaae4..dfb9d64d 100644 --- a/Core/HdNesPack.h +++ b/Core/HdNesPack.h @@ -11,7 +11,7 @@ private: __forceinline void BlendColors(uint8_t output[4], uint8_t input[4]); __forceinline uint32_t AdjustBrightness(uint8_t input[4], uint16_t brightness); __forceinline void DrawColor(uint32_t color, uint32_t* outputBuffer, uint32_t scale, uint32_t screenWidth); - __forceinline bool DrawTile(HdPpuTileInfo &tileInfo, HdPackTileInfo &hdPackTileInfo, uint32_t* outputBuffer, uint32_t screenWidth, bool drawBackground); + __forceinline void DrawTile(HdPpuTileInfo &tileInfo, HdPackTileInfo &hdPackTileInfo, uint32_t* outputBuffer, uint32_t screenWidth); __forceinline HdPackTileInfo* GetMatchingTile(HdPpuPixelInfo *screenTiles, uint32_t x, uint32_t y, HdTileKey& key); __forceinline bool IsNextToSprite(HdPpuPixelInfo *screenTiles, uint32_t x, uint32_t y); diff --git a/Core/HdPackBuilder.cpp b/Core/HdPackBuilder.cpp index ad205eae..efda3814 100644 --- a/Core/HdPackBuilder.cpp +++ b/Core/HdPackBuilder.cpp @@ -76,10 +76,11 @@ void HdPackBuilder::AddTile(HdPackTileInfo *tile, uint32_t usageCount) paletteMap[palette][tile->TileIndex % 256] = tile; } + _tilesByKey[tile->GetKey(false)] = tile; _tileUsageCount[tile->GetKey(false)] = usageCount; } -void HdPackBuilder::ProcessTile(uint32_t x, uint32_t y, uint16_t tileAddr, HdPpuTileInfo &tile, BaseMapper *mapper, bool isSprite, uint32_t chrBankHash) +void HdPackBuilder::ProcessTile(uint32_t x, uint32_t y, uint16_t tileAddr, HdPpuTileInfo &tile, BaseMapper *mapper, bool isSprite, uint32_t chrBankHash, bool transparencyRequired) { if(_flags & HdPackRecordFlags::IgnoreOverscan) { OverscanDimensions overscan = EmulationSettings::GetOverscanDimensions(); @@ -104,14 +105,20 @@ void HdPackBuilder::ProcessTile(uint32_t x, uint32_t y, uint16_t tileAddr, HdPpu hdTile->IsChrRamTile = _isChrRam; hdTile->Brightness = 255; hdTile->ChrBankId = _isChrRam ? chrBankHash : (tileAddr / 16 / 256); + hdTile->TransparencyRequired = transparencyRequired; memcpy(hdTile->TileData, tile.TileData, 16); - GenerateHdTile(hdTile); - hdTile->UpdateFlags(); _hdData.Tiles.push_back(unique_ptr(hdTile)); AddTile(hdTile, 1); } else { + if(transparencyRequired) { + auto existingTile = _tilesByKey.find(tile.GetKey(false)); + if(existingTile != _tilesByKey.end()) { + existingTile->second->TransparencyRequired = true; + } + } + if(result->second < 0x7FFFFFFF) { //Increase usage count result->second++; @@ -166,6 +173,11 @@ void HdPackBuilder::GenerateHdTile(HdPackTileInfo *tile) void HdPackBuilder::DrawTile(HdPackTileInfo *tile, int tileNumber, uint32_t *pngBuffer, int pageNumber, bool containsSpritesOnly) { + if(tile->HdTileData.empty()) { + GenerateHdTile(tile); + tile->UpdateFlags(); + } + if(containsSpritesOnly && (_flags & HdPackRecordFlags::UseLargeSprites)) { int row = tileNumber / 16; int column = tileNumber % 16; diff --git a/Core/HdPackBuilder.h b/Core/HdPackBuilder.h index 957775c8..731d6905 100644 --- a/Core/HdPackBuilder.h +++ b/Core/HdPackBuilder.h @@ -21,6 +21,7 @@ private: HdPackData _hdData; std::unordered_map _tileUsageCount; + std::unordered_map _tilesByKey; std::map>> _tilesByChrBankByPalette; bool _isChrRam; uint32_t _chrRamBankSize; @@ -41,7 +42,7 @@ public: HdPackBuilder(string saveFolder, ScaleFilterType filterType, uint32_t scale, uint32_t flags, uint32_t chrRamBankSize, bool isChrRam); ~HdPackBuilder(); - void ProcessTile(uint32_t x, uint32_t y, uint16_t tileAddr, HdPpuTileInfo& tile, BaseMapper* mapper, bool isSprite, uint32_t chrBankHash); + void ProcessTile(uint32_t x, uint32_t y, uint16_t tileAddr, HdPpuTileInfo& tile, BaseMapper* mapper, bool isSprite, uint32_t chrBankHash, bool transparencyRequired); void SaveHdPack(); static void GetChrBankList(uint32_t *banks);