From fda119afcac67508675d8b2e3ae80962229462b6 Mon Sep 17 00:00:00 2001 From: Sour Date: Sun, 11 Mar 2018 22:42:32 -0400 Subject: [PATCH] HD Packs: Added support for grayscale and emphasis bits --- Core/HdData.h | 2 ++ Core/HdNesPack.cpp | 56 ++++++++++++++++++++++++++++++++++++++++++++++ Core/HdNesPack.h | 1 + Core/HdPpu.h | 2 ++ 4 files changed, 61 insertions(+) diff --git a/Core/HdData.h b/Core/HdData.h index 8d5d67d4..eb51fc3a 100644 --- a/Core/HdData.h +++ b/Core/HdData.h @@ -96,6 +96,8 @@ struct HdPpuPixelInfo uint16_t TmpVideoRamAddr; uint8_t XScroll; + uint8_t EmphasisBits; + bool Grayscale; HdPpuPixelInfo() { diff --git a/Core/HdNesPack.cpp b/Core/HdNesPack.cpp index e0ffc971..c902f7b5 100644 --- a/Core/HdNesPack.cpp +++ b/Core/HdNesPack.cpp @@ -358,9 +358,65 @@ void HdNesPack::Process(HdScreenInfo *hdScreenInfo, uint32_t* outputBuffer, Over for(uint32_t i = overscan.Top, iMax = 240 - overscan.Bottom; i < iMax; i++) { OnLineStart(hdScreenInfo->ScreenTiles[i << 8]); uint32_t bufferIndex = (i - overscan.Top) * screenWidth * hdScale; + uint32_t lineStartIndex = bufferIndex; for(uint32_t j = overscan.Left, jMax = 256 - overscan.Right; j < jMax; j++) { GetPixels(j, i, hdScreenInfo->ScreenTiles[i * 256 + j], outputBuffer + bufferIndex, screenWidth); bufferIndex += hdScale; } + + ProcessGrayscaleAndEmphasis(hdScreenInfo->ScreenTiles[i * 256], outputBuffer + lineStartIndex, screenWidth); + } +} + +void HdNesPack::ProcessGrayscaleAndEmphasis(HdPpuPixelInfo &pixelInfo, uint32_t* outputBuffer, uint32_t hdScreenWidth) +{ + //Apply grayscale/emphasis bits on a scanline level (less accurate, but shouldn't cause issues and simpler to implement) + uint32_t scale = GetScale(); + if(pixelInfo.Grayscale) { + uint32_t* out = outputBuffer; + for(uint32_t y = 0; y < scale; y++) { + for(uint32_t x = 0; x < hdScreenWidth; x++) { + uint32_t &rgbValue = out[x]; + uint8_t average = (((rgbValue >> 16) & 0xFF) + ((rgbValue >> 8) & 0xFF) + (rgbValue & 0xFF)) / 3; + rgbValue = (rgbValue & 0xFF000000) | (average << 16) | (average << 8) | average; + } + out += hdScreenWidth; + } + } + + if(pixelInfo.EmphasisBits) { + uint8_t emphasisBits = pixelInfo.EmphasisBits; + double red = 1.0, green = 1.0, blue = 1.0; + if(emphasisBits & 0x01) { + //Intensify red + red *= 1.1; + green *= 0.9; + blue *= 0.9; + } + if(emphasisBits & 0x02) { + //Intensify green + green *= 1.1; + red *= 0.9; + blue *= 0.9; + } + if(emphasisBits & 0x04) { + //Intensify blue + blue *= 1.1; + red *= 0.9; + green *= 0.9; + } + + uint32_t* out = outputBuffer; + for(uint32_t y = 0; y < scale; y++) { + for(uint32_t x = 0; x < hdScreenWidth; x++) { + uint32_t &rgbValue = out[x]; + + rgbValue = 0xFF000000 | + (std::min((uint16_t)(((rgbValue >> 16) & 0xFF) * red), 255) << 16) | + (std::min((uint16_t)(((rgbValue >> 8) & 0xFF) * green), 255) << 8) | + std::min((uint16_t)((rgbValue & 0xFF) * blue), 255); + } + out += hdScreenWidth; + } } } \ No newline at end of file diff --git a/Core/HdNesPack.h b/Core/HdNesPack.h index dd9f20d6..b43bf8a4 100644 --- a/Core/HdNesPack.h +++ b/Core/HdNesPack.h @@ -30,6 +30,7 @@ private: void OnLineStart(HdPpuPixelInfo &lineFirstPixel); void OnBeforeApplyFilter(); __forceinline void GetPixels(uint32_t x, uint32_t y, HdPpuPixelInfo &pixelInfo, uint32_t *outputBuffer, uint32_t screenWidth); + __forceinline void ProcessGrayscaleAndEmphasis(HdPpuPixelInfo &pixelInfo, uint32_t* outputBuffer, uint32_t hdScreenWidth); public: static const uint32_t CurrentVersion = 101; diff --git a/Core/HdPpu.h b/Core/HdPpu.h index c4fb1023..944650c3 100644 --- a/Core/HdPpu.h +++ b/Core/HdPpu.h @@ -36,6 +36,8 @@ protected: HdPpuPixelInfo &tileInfo = _info->ScreenTiles[bufferOffset]; + tileInfo.Grayscale = _paletteRamMask == 0x30; + tileInfo.EmphasisBits = _intensifyColorBits >> 6; tileInfo.Tile.PpuBackgroundColor = ReadPaletteRAM(0); tileInfo.Tile.BgColorIndex = backgroundColor; if(backgroundColor == 0) {