PPU: Window support (except color window)
This commit is contained in:
parent
7f5d93d680
commit
a009e899a2
3 changed files with 174 additions and 2 deletions
130
Core/Ppu.cpp
130
Core/Ppu.cpp
|
@ -126,17 +126,32 @@ void Ppu::Exec()
|
|||
template<uint8_t priority, bool forMainScreen>
|
||||
void Ppu::RenderSprites()
|
||||
{
|
||||
uint8_t activeWindowCount = 0;
|
||||
if(forMainScreen) {
|
||||
if(_pixelsDrawn == 256 || (_mainScreenLayers & 0x10) == 0) {
|
||||
return;
|
||||
}
|
||||
} else if(_subPixelsDrawn == 256 || (_subScreenLayers & 0x10) == 0) {
|
||||
return;
|
||||
if(_windowMaskMain[Ppu::SpriteLayerIndex]) {
|
||||
activeWindowCount = (uint8_t)_window[0].ActiveLayers[Ppu::SpriteLayerIndex] + (uint8_t)_window[1].ActiveLayers[Ppu::SpriteLayerIndex];
|
||||
}
|
||||
} else {
|
||||
if(_subPixelsDrawn == 256 || (_subScreenLayers & 0x10) == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
if(_windowMaskSub[Ppu::SpriteLayerIndex]) {
|
||||
activeWindowCount = (uint8_t)_window[0].ActiveLayers[Ppu::SpriteLayerIndex] + (uint8_t)_window[1].ActiveLayers[Ppu::SpriteLayerIndex];
|
||||
}
|
||||
}
|
||||
|
||||
if(forMainScreen) {
|
||||
for(int x = 0; x < 256; x++) {
|
||||
if(!_rowPixelFlags[x] && _spritePriority[x] == priority) {
|
||||
if(activeWindowCount && ProcessMaskWindow<Ppu::SpriteLayerIndex>(activeWindowCount, x)) {
|
||||
//This pixel was masked
|
||||
continue;
|
||||
}
|
||||
|
||||
_currentBuffer[(_scanline << 8) | x] = _spritePixels[x];
|
||||
_rowPixelFlags[x] |= PixelFlags::Filled | (((_colorMathEnabled & 0x10) && _spritePalette[x] > 3) ? PixelFlags::AllowColorMath : 0);
|
||||
}
|
||||
|
@ -144,6 +159,11 @@ void Ppu::RenderSprites()
|
|||
} else {
|
||||
for(int x = 0; x < 256; x++) {
|
||||
if(!_subScreenFilled[x] && _spritePriority[x] == priority) {
|
||||
if(activeWindowCount && ProcessMaskWindow<Ppu::SpriteLayerIndex>(activeWindowCount, x)) {
|
||||
//This pixel was masked
|
||||
continue;
|
||||
}
|
||||
|
||||
_subScreenBuffer[x] = _spritePixels[x];
|
||||
_subScreenFilled[x] = true;
|
||||
}
|
||||
|
@ -431,6 +451,11 @@ void Ppu::RenderTilemap()
|
|||
}
|
||||
}
|
||||
|
||||
uint8_t activeWindowCount = 0;
|
||||
if((forMainScreen && _windowMaskMain[layerIndex]) || (!forMainScreen && _windowMaskSub[layerIndex])) {
|
||||
activeWindowCount = (uint8_t)_window[0].ActiveLayers[layerIndex] + (uint8_t)_window[1].ActiveLayers[layerIndex];
|
||||
}
|
||||
|
||||
bool applyMosaic = forMainScreen && ((_mosaicEnabled >> layerIndex) & 0x01) != 0;
|
||||
bool mosaicScanline = applyMosaic && (_scanline - _mosaicStartScanline) % _mosaicSize != 0;
|
||||
|
||||
|
@ -459,6 +484,11 @@ void Ppu::RenderTilemap()
|
|||
}
|
||||
}
|
||||
|
||||
if(activeWindowCount && ProcessMaskWindow<layerIndex>(activeWindowCount, x)) {
|
||||
//This pixel was masked
|
||||
continue;
|
||||
}
|
||||
|
||||
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];
|
||||
|
@ -569,6 +599,39 @@ void Ppu::ApplyColorMath()
|
|||
}
|
||||
}
|
||||
|
||||
template<uint8_t layerIndex>
|
||||
bool Ppu::ProcessMaskWindow(uint8_t activeWindowCount, int x)
|
||||
{
|
||||
if(activeWindowCount == 1) {
|
||||
if(_window[0].ActiveLayers[layerIndex]) {
|
||||
return _window[0].PixelNeedsMasking<layerIndex>(x);
|
||||
} else {
|
||||
return _window[1].PixelNeedsMasking<layerIndex>(x);
|
||||
}
|
||||
} else {
|
||||
switch(_maskLogic[layerIndex]) {
|
||||
default:
|
||||
case WindowMaskLogic::Or: return _window[0].PixelNeedsMasking<layerIndex>(x) | _window[1].PixelNeedsMasking<layerIndex>(x);
|
||||
case WindowMaskLogic::And: return _window[0].PixelNeedsMasking<layerIndex>(x) & _window[1].PixelNeedsMasking<layerIndex>(x);
|
||||
case WindowMaskLogic::Xor: return _window[0].PixelNeedsMasking<layerIndex>(x) ^ _window[1].PixelNeedsMasking<layerIndex>(x);
|
||||
case WindowMaskLogic::Xnor: return !(_window[0].PixelNeedsMasking<layerIndex>(x) ^ _window[1].PixelNeedsMasking<layerIndex>(x));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Ppu::ProcessWindowMaskSettings(uint8_t value, uint8_t offset)
|
||||
{
|
||||
_window[0].ActiveLayers[0 + offset] = (value & 0x02) != 0;
|
||||
_window[0].ActiveLayers[1 + offset] = (value & 0x20) != 0;
|
||||
_window[0].InvertedLayers[0 + offset] = (value & 0x01) != 0;
|
||||
_window[0].InvertedLayers[1 + offset] = (value & 0x10) != 0;
|
||||
|
||||
_window[1].ActiveLayers[0 + offset] = (value & 0x08) != 0;
|
||||
_window[1].ActiveLayers[1 + offset] = (value & 0x80) != 0;
|
||||
_window[1].InvertedLayers[0 + offset] = (value & 0x04) != 0;
|
||||
_window[1].InvertedLayers[1 + offset] = (value & 0x40) != 0;
|
||||
}
|
||||
|
||||
void Ppu::SendFrame()
|
||||
{
|
||||
_console->GetNotificationManager()->SendNotification(ConsoleNotificationType::PpuFrameDone);
|
||||
|
@ -876,6 +939,55 @@ void Ppu::Write(uint32_t addr, uint8_t value)
|
|||
_cgramAddress = (_cgramAddress + 1) & (Ppu::CgRamSize - 1);
|
||||
break;
|
||||
|
||||
case 0x2123:
|
||||
//W12SEL - Window Mask Settings for BG1 and BG2
|
||||
ProcessWindowMaskSettings(value, 0);
|
||||
break;
|
||||
|
||||
case 0x2124:
|
||||
//W34SEL - Window Mask Settings for BG3 and BG4
|
||||
ProcessWindowMaskSettings(value, 2);
|
||||
break;
|
||||
|
||||
case 0x2125:
|
||||
//WOBJSEL - Window Mask Settings for OBJ and Color Window
|
||||
ProcessWindowMaskSettings(value, 4);
|
||||
break;
|
||||
|
||||
case 0x2126:
|
||||
//WH0 - Window 1 Left Position
|
||||
_window[0].Left = value;
|
||||
break;
|
||||
|
||||
case 0x2127:
|
||||
//WH1 - Window 1 Right Position
|
||||
_window[0].Right = value;
|
||||
break;
|
||||
|
||||
case 0x2128:
|
||||
//WH2 - Window 2 Left Position
|
||||
_window[1].Left = value;
|
||||
break;
|
||||
|
||||
case 0x2129:
|
||||
//WH3 - Window 2 Right Position
|
||||
_window[1].Right = value;
|
||||
break;
|
||||
|
||||
case 0x212A:
|
||||
//WBGLOG - Window mask logic for BG
|
||||
_maskLogic[0] = (WindowMaskLogic)(value & 0x03);
|
||||
_maskLogic[1] = (WindowMaskLogic)((value >> 2) & 0x03);
|
||||
_maskLogic[2] = (WindowMaskLogic)((value >> 4) & 0x03);
|
||||
_maskLogic[3] = (WindowMaskLogic)((value >> 6) & 0x03);
|
||||
break;
|
||||
|
||||
case 0x212B:
|
||||
//WOBJLOG - Window mask logic for OBJs and Color Window
|
||||
_maskLogic[5] = (WindowMaskLogic)((value >> 0) & 0x03);
|
||||
_maskLogic[6] = (WindowMaskLogic)((value >> 2) & 0x03);
|
||||
break;
|
||||
|
||||
case 0x212C:
|
||||
//TM - Main Screen Designation
|
||||
_mainScreenLayers = value & 0x1F;
|
||||
|
@ -885,6 +997,20 @@ void Ppu::Write(uint32_t addr, uint8_t value)
|
|||
//TS - Subscreen Designation
|
||||
_subScreenLayers = value & 0x1F;
|
||||
break;
|
||||
|
||||
case 0x212E:
|
||||
//TMW - Window Mask Designation for the Main Screen
|
||||
for(int i = 0; i < 5; i++) {
|
||||
_windowMaskMain[i] = ((value >> i) & 0x01) != 0;
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x212F:
|
||||
//TSW - Window Mask Designation for the Subscreen
|
||||
for(int i = 0; i < 5; i++) {
|
||||
_windowMaskSub[i] = ((value >> i) & 0x01) != 0;
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x2130:
|
||||
//CGWSEL - Color Addition Select
|
||||
|
|
12
Core/Ppu.h
12
Core/Ppu.h
|
@ -27,6 +27,8 @@ public:
|
|||
constexpr static uint32_t VideoRamSize = 0x10000;
|
||||
|
||||
private:
|
||||
constexpr static int SpriteLayerIndex = 4;
|
||||
|
||||
constexpr static const uint8_t _oamSizes[8][2][2] = {
|
||||
{ { 1, 1 }, { 2, 2 } }, //8x8 + 16x16
|
||||
{ { 1, 1 }, { 4, 4 } }, //8x8 + 32x32
|
||||
|
@ -54,6 +56,11 @@ private:
|
|||
uint8_t _mainScreenLayers = 0;
|
||||
uint8_t _subScreenLayers = 0;
|
||||
LayerConfig _layerConfig[4];
|
||||
|
||||
WindowConfig _window[2];
|
||||
WindowMaskLogic _maskLogic[6];
|
||||
bool _windowMaskMain[5];
|
||||
bool _windowMaskSub[5];
|
||||
|
||||
uint8_t *_vram;
|
||||
uint16_t _vramAddress;
|
||||
|
@ -150,6 +157,11 @@ private:
|
|||
|
||||
void RenderScanline();
|
||||
void ApplyColorMath();
|
||||
|
||||
template<uint8_t layerIndex>
|
||||
bool ProcessMaskWindow(uint8_t activeWindowCount, int x);
|
||||
void ProcessWindowMaskSettings(uint8_t value, uint8_t offset);
|
||||
|
||||
void SendFrame();
|
||||
|
||||
public:
|
||||
|
|
|
@ -20,4 +20,38 @@ struct LayerConfig
|
|||
bool VerticalMirroring;
|
||||
|
||||
bool LargeTiles;
|
||||
};
|
||||
|
||||
struct WindowConfig
|
||||
{
|
||||
bool ActiveLayers[6];
|
||||
bool InvertedLayers[6];
|
||||
uint8_t Left;
|
||||
uint8_t Right;
|
||||
|
||||
template<uint8_t layerIndex>
|
||||
bool PixelNeedsMasking(int x)
|
||||
{
|
||||
if(InvertedLayers[layerIndex]) {
|
||||
if(Left > Right) {
|
||||
return true;
|
||||
} else {
|
||||
return x < Left || x > Right;
|
||||
}
|
||||
} else {
|
||||
if(Left > Right) {
|
||||
return false;
|
||||
} else {
|
||||
return x >= Left && x <= Right;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
enum class WindowMaskLogic
|
||||
{
|
||||
Or = 0,
|
||||
And = 1,
|
||||
Xor = 2,
|
||||
Xnor = 3
|
||||
};
|
Loading…
Add table
Reference in a new issue