From 37b501122fbb094eb688b66defe5692986423c8f Mon Sep 17 00:00:00 2001 From: Sour Date: Wed, 20 Feb 2019 17:39:14 -0500 Subject: [PATCH] PPU: Mosaic effect support --- Core/Ppu.cpp | 31 ++++++++++++++++++++++++++++++- Core/Ppu.h | 5 +++++ 2 files changed, 35 insertions(+), 1 deletion(-) diff --git a/Core/Ppu.cpp b/Core/Ppu.cpp index 77d2471..f482dc7 100644 --- a/Core/Ppu.cpp +++ b/Core/Ppu.cpp @@ -93,6 +93,9 @@ void Ppu::Exec() } else if(_scanline == 261) { _regs->SetNmiFlag(false); _scanline = 0; + if(_mosaicEnabled) { + _mosaicStartScanline = 0; + } _console->GetDmaController()->InitHdmaChannels(); RenderScanline(); } @@ -378,12 +381,15 @@ void Ppu::RenderTilemap() } } + bool applyMosaic = forMainScreen && ((_mosaicEnabled >> layerIndex) & 0x01) != 0; + bool mosaicScanline = applyMosaic && (_scanline - _mosaicStartScanline) % _mosaicSize != 0; + uint8_t pixelFlags = PixelFlags::Filled | (((_colorMathEnabled >> layerIndex) & 0x01) ? PixelFlags::AllowColorMath : 0); LayerConfig &config = _layerConfig[layerIndex]; uint16_t tilemapAddr = config.TilemapAddress >> 1; uint16_t chrAddr = config.ChrAddress; - + for(int x = 0; x < 256; x++) { uint16_t row = (_scanline + config.VScroll) >> 3; uint16_t column = (x + config.HScroll) >> 3; @@ -401,6 +407,13 @@ void Ppu::RenderTilemap() } } + if(mosaicScanline || (applyMosaic && x % _mosaicSize != 0)) { + //If this is not the top-left pixels in the mosaic pattern, override it with the top-left pixel data + _currentBuffer[(_scanline << 8) | x] = _mosaicColor[x]; + _rowPixelFlags[x] = pixelFlags; + continue; + } + uint8_t palette = (_vram[addr + 1] >> 2) & 0x07; uint16_t tileIndex = ((_vram[addr + 1] & 0x03) << 8) | _vram[addr]; bool vMirror = (_vram[addr + 1] & 0x80) != 0; @@ -430,6 +443,12 @@ void Ppu::RenderTilemap() if(forMainScreen) { _currentBuffer[(_scanline << 8) | x] = paletteColor; _rowPixelFlags[x] = pixelFlags; + if(applyMosaic && x % _mosaicSize == 0) { + //This is the source for the mosaic pattern, store it for use in the next scanlines + for(int i = 0; i < _mosaicSize && x + i < 256; i++) { + _mosaicColor[x+i] = paletteColor; + } + } } else { _subScreenBuffer[(_scanline << 8) | x] = paletteColor; _subScreenFilled[x] = true; @@ -588,6 +607,16 @@ void Ppu::Write(uint32_t addr, uint8_t value) _layerConfig[3].LargeTiles = (value & 0x40) != 0; break; + case 0x2106: + //MOSAIC - Screen Pixelation + _mosaicSize = ((value & 0xF0) >> 4) + 1; + _mosaicEnabled = value & 0x0F; + if(_mosaicEnabled) { + //"If this register is set during the frame, the estarting scanlinef is the current scanline, otherwise it is the first visible scanline of the frame." + _mosaicStartScanline = _scanline; + } + break; + case 0x2107: case 0x2108: case 0x2109: case 0x210A: //BG 1-4 Tilemap Address and Size (BG1SC, BG2SC, BG3SC, BG4SC) _layerConfig[addr - 0x2107].TilemapAddress = (value & 0xFC) << 9; diff --git a/Core/Ppu.h b/Core/Ppu.h index ff9c2ae..a710348 100644 --- a/Core/Ppu.h +++ b/Core/Ppu.h @@ -78,6 +78,11 @@ private: bool _subScreenFilled[256]; uint16_t *_subScreenBuffer; + uint16_t _mosaicColor[256] = {}; + uint8_t _mosaicSize = 0; + uint8_t _mosaicEnabled = 0; + uint16_t _mosaicStartScanline = 0; + uint8_t _oamMode = 0; uint16_t _oamBaseAddress = 0; uint16_t _oamAddressOffset = 0;