PPU: Scanline renderer (wip) - better priority & subscreen/color math logic
This commit is contained in:
parent
ad251609d6
commit
d88a0b5086
2 changed files with 237 additions and 175 deletions
340
Core/Ppu.cpp
340
Core/Ppu.cpp
|
@ -16,6 +16,7 @@ Ppu::Ppu(shared_ptr<Console> console)
|
||||||
|
|
||||||
_outputBuffers[0] = new uint16_t[256 * 224];
|
_outputBuffers[0] = new uint16_t[256 * 224];
|
||||||
_outputBuffers[1] = new uint16_t[256 * 224];
|
_outputBuffers[1] = new uint16_t[256 * 224];
|
||||||
|
_subScreenBuffer = new uint16_t[256 * 224];
|
||||||
|
|
||||||
_currentBuffer = _outputBuffers[0];
|
_currentBuffer = _outputBuffers[0];
|
||||||
|
|
||||||
|
@ -38,6 +39,7 @@ Ppu::Ppu(shared_ptr<Console> console)
|
||||||
Ppu::~Ppu()
|
Ppu::~Ppu()
|
||||||
{
|
{
|
||||||
delete[] _vram;
|
delete[] _vram;
|
||||||
|
delete[] _subScreenBuffer;
|
||||||
delete[] _outputBuffers[0];
|
delete[] _outputBuffers[0];
|
||||||
delete[] _outputBuffers[1];
|
delete[] _outputBuffers[1];
|
||||||
}
|
}
|
||||||
|
@ -61,7 +63,7 @@ void Ppu::Exec()
|
||||||
if(_cycle == 340) {
|
if(_cycle == 340) {
|
||||||
_cycle = -1;
|
_cycle = -1;
|
||||||
_scanline++;
|
_scanline++;
|
||||||
if(_scanline < 225) {
|
if(_scanline < 224) {
|
||||||
RenderScanline();
|
RenderScanline();
|
||||||
} else if(_scanline == 225) {
|
} else if(_scanline == 225) {
|
||||||
//Reset OAM address at the start of vblank?
|
//Reset OAM address at the start of vblank?
|
||||||
|
@ -80,6 +82,7 @@ void Ppu::Exec()
|
||||||
} else if(_scanline == 261) {
|
} else if(_scanline == 261) {
|
||||||
_regs->SetNmiFlag(false);
|
_regs->SetNmiFlag(false);
|
||||||
_scanline = 0;
|
_scanline = 0;
|
||||||
|
RenderScanline();
|
||||||
}
|
}
|
||||||
|
|
||||||
if(_regs->IsVerticalIrqEnabled() && !_regs->IsHorizontalIrqEnabled() && _scanline == _regs->GetVerticalTimer()) {
|
if(_regs->IsVerticalIrqEnabled() && !_regs->IsHorizontalIrqEnabled() && _scanline == _regs->GetVerticalTimer()) {
|
||||||
|
@ -115,18 +118,123 @@ uint8_t _spriteCount = 0;
|
||||||
uint8_t _spritePriority[256] = {};
|
uint8_t _spritePriority[256] = {};
|
||||||
uint16_t _spritePixels[256] = {};
|
uint16_t _spritePixels[256] = {};
|
||||||
|
|
||||||
void Ppu::RenderScanline()
|
template<uint8_t priority, bool forMainScreen>
|
||||||
|
void Ppu::DrawSprites()
|
||||||
{
|
{
|
||||||
|
if(forMainScreen) {
|
||||||
for(int x = 0; x < 256; x++) {
|
for(int x = 0; x < 256; x++) {
|
||||||
if(_spritePriority[x] != 0xFF && _spritePixels[x] != 0xFFFF) {
|
if(!_filled[x] && _spritePriority[x] == priority) {
|
||||||
_currentBuffer[(_scanline << 8) | x] = _spritePixels[x];
|
_currentBuffer[(_scanline << 8) | x] = _spritePixels[x];
|
||||||
|
_filled[x] = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for(int x = 0; x < 256; x++) {
|
||||||
|
if(!_subScreenFilled[x] && _spritePriority[x] == priority) {
|
||||||
|
_subScreenBuffer[(_scanline << 8) | x] = _spritePixels[x];
|
||||||
|
_subScreenFilled[x] = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* switch(_bgMode) {
|
void Ppu::RenderScanline()
|
||||||
case 1:
|
{
|
||||||
|
memset(_filled, 0, sizeof(_filled));
|
||||||
|
memset(_subScreenFilled, 0, sizeof(_subScreenFilled));
|
||||||
|
|
||||||
|
switch(_bgMode) {
|
||||||
|
case 0:
|
||||||
|
DrawSprites<3, true>();
|
||||||
|
RenderTilemap<0, 2, true, true>();
|
||||||
|
RenderTilemap<1, 2, true, true>();
|
||||||
|
DrawSprites<2, true>();
|
||||||
|
RenderTilemap<0, 2, false, true>();
|
||||||
|
RenderTilemap<1, 2, false, true>();
|
||||||
|
DrawSprites<1, true>();
|
||||||
|
RenderTilemap<2, 2, true, true>();
|
||||||
|
RenderTilemap<3, 2, true, true>();
|
||||||
|
DrawSprites<0, true>();
|
||||||
|
RenderTilemap<2, 2, false, true>();
|
||||||
|
RenderTilemap<3, 2, false, true>();
|
||||||
|
RenderBgColor<true>();
|
||||||
break;
|
break;
|
||||||
}*/
|
|
||||||
|
case 1:
|
||||||
|
//Main screen
|
||||||
|
if(_mode1Bg3Priority) {
|
||||||
|
RenderTilemap<2, 2, true, true>();
|
||||||
|
}
|
||||||
|
DrawSprites<3, true>();
|
||||||
|
RenderTilemap<0, 4, true, true>();
|
||||||
|
RenderTilemap<1, 4, true, true>();
|
||||||
|
DrawSprites<2, true>();
|
||||||
|
RenderTilemap<0, 4, false, true>();
|
||||||
|
RenderTilemap<1, 4, false, true>();
|
||||||
|
DrawSprites<1, true>();
|
||||||
|
if(!_mode1Bg3Priority) {
|
||||||
|
RenderTilemap<2, 2, true, true>();
|
||||||
|
}
|
||||||
|
DrawSprites<0, true>();
|
||||||
|
RenderTilemap<2, 2, false, true>();
|
||||||
|
RenderBgColor<true>();
|
||||||
|
|
||||||
|
//Subscreen
|
||||||
|
if(_mode1Bg3Priority) {
|
||||||
|
RenderTilemap<2, 2, true, false>();
|
||||||
|
}
|
||||||
|
DrawSprites<3, false>();
|
||||||
|
RenderTilemap<0, 4, true, false>();
|
||||||
|
RenderTilemap<1, 4, true, false>();
|
||||||
|
DrawSprites<2, false>();
|
||||||
|
RenderTilemap<0, 4, false, false>();
|
||||||
|
RenderTilemap<1, 4, false, false>();
|
||||||
|
DrawSprites<1, false>();
|
||||||
|
if(!_mode1Bg3Priority) {
|
||||||
|
RenderTilemap<2, 2, true, false>();
|
||||||
|
}
|
||||||
|
DrawSprites<0, true>();
|
||||||
|
RenderTilemap<2, 2, false, false>();
|
||||||
|
RenderBgColor<false>();
|
||||||
|
|
||||||
|
ApplyColorMath();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 2:
|
||||||
|
DrawSprites<3, true>();
|
||||||
|
RenderTilemap<0, 4, true, true>();
|
||||||
|
DrawSprites<2, true>();
|
||||||
|
RenderTilemap<1, 4, true, true>();
|
||||||
|
DrawSprites<1, true>();
|
||||||
|
RenderTilemap<0, 4, false, true>();
|
||||||
|
DrawSprites<0, true>();
|
||||||
|
RenderTilemap<1, 4, false, true>();
|
||||||
|
RenderBgColor<true>();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 3:
|
||||||
|
DrawSprites<3, true>();
|
||||||
|
RenderTilemap<0, 8, true, true>();
|
||||||
|
DrawSprites<2, true>();
|
||||||
|
RenderTilemap<1, 4, true, true>();
|
||||||
|
DrawSprites<1, true>();
|
||||||
|
RenderTilemap<0, 8, false, true>();
|
||||||
|
DrawSprites<0, true>();
|
||||||
|
RenderTilemap<1, 4, false, true>();
|
||||||
|
RenderBgColor<true>();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 5:
|
||||||
|
RenderTilemap<1, 2, false, true>();
|
||||||
|
RenderTilemap<0, 4, false, true>();
|
||||||
|
RenderBgColor<true>();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 6:
|
||||||
|
RenderTilemap<0, 8, false, true>();
|
||||||
|
RenderBgColor<true>();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
//Process sprites for next scanline
|
//Process sprites for next scanline
|
||||||
memset(_spritePriority, 0xFF, sizeof(_spritePriority));
|
memset(_spritePriority, 0xFF, sizeof(_spritePriority));
|
||||||
|
@ -141,7 +249,7 @@ void Ppu::RenderScanline()
|
||||||
uint8_t largeSprite = (highTableValue & 0x02) >> 1;
|
uint8_t largeSprite = (highTableValue & 0x02) >> 1;
|
||||||
uint8_t height = _oamSizes[_oamMode][largeSprite][1] << 3;
|
uint8_t height = _oamSizes[_oamMode][largeSprite][1] << 3;
|
||||||
|
|
||||||
if(y > _scanline + 1 || y + height < _scanline + 1) {
|
if(y > _scanline + 1 || y + height <= _scanline + 1) {
|
||||||
//Not visible on this scanline
|
//Not visible on this scanline
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -180,8 +288,8 @@ void Ppu::RenderScanline()
|
||||||
uint8_t xOffset;
|
uint8_t xOffset;
|
||||||
int columnOffset;
|
int columnOffset;
|
||||||
if(info.HorizontalMirror) {
|
if(info.HorizontalMirror) {
|
||||||
xOffset = (width - (x - info.X)) & 0x07;
|
xOffset = (width - (x - info.X) - 1) & 0x07;
|
||||||
columnOffset = (width - (x - info.X)) >> 3;
|
columnOffset = (width - (x - info.X) - 1) >> 3;
|
||||||
} else {
|
} else {
|
||||||
xOffset = (x - info.X) & 0x07;
|
xOffset = (x - info.X) & 0x07;
|
||||||
columnOffset = (x - info.X) >> 3;
|
columnOffset = (x - info.X) >> 3;
|
||||||
|
@ -215,37 +323,71 @@ void Ppu::RenderScanline()
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Ppu::RenderTilemap(uint8_t layerIndex, uint8_t bpp)
|
template<bool forMainScreen>
|
||||||
|
void Ppu::RenderBgColor()
|
||||||
{
|
{
|
||||||
|
uint16_t bgColor = _cgram[0] | (_cgram[1] << 8);
|
||||||
|
for(int x = 0; x < 256; x++) {
|
||||||
|
if(forMainScreen) {
|
||||||
|
if(!_filled[x]) {
|
||||||
|
_currentBuffer[(_scanline << 8) | x] = bgColor;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if(!_subScreenFilled[x]) {
|
||||||
|
_subScreenBuffer[(_scanline << 8) | x] = bgColor;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template<uint8_t layerIndex, uint8_t bpp, bool processHighPriority, bool forMainScreen>
|
||||||
|
void Ppu::RenderTilemap()
|
||||||
|
{
|
||||||
|
if(forMainScreen) {
|
||||||
if(((_mainScreenLayers >> layerIndex) & 0x01) == 0) {
|
if(((_mainScreenLayers >> layerIndex) & 0x01) == 0) {
|
||||||
//This screen is disabled
|
//This screen is disabled
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
bool useColorMath = ((_colorMathEnabled >> layerIndex) & 0x01) != 0;
|
if(((_subScreenLayers >> layerIndex) & 0x01) == 0) {
|
||||||
|
//This screen is disabled
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
LayerConfig &config = _layerConfig[layerIndex];
|
LayerConfig &config = _layerConfig[layerIndex];
|
||||||
|
|
||||||
uint16_t tilemapAddr = config.TilemapAddress;
|
uint16_t tilemapAddr = config.TilemapAddress;
|
||||||
uint16_t chrAddr = config.ChrAddress;
|
uint16_t chrAddr = config.ChrAddress;
|
||||||
|
uint32_t addr = tilemapAddr + ((_scanline >> 3) << 6) - 2;
|
||||||
|
|
||||||
|
for(int x = 0; x < 256; x++) {
|
||||||
|
if((x & 0x07) == 0) {
|
||||||
|
addr += 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(forMainScreen) {
|
||||||
|
if(_filled[x] || ((uint8_t)processHighPriority != ((_vram[addr + 1] & 0x20) >> 5))) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if(_subScreenFilled[x] || ((uint8_t)processHighPriority != ((_vram[addr + 1] & 0x20) >> 5))) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
uint32_t addr = tilemapAddr;
|
|
||||||
for(int y = 0; y < 28; y++) {
|
|
||||||
for(int x = 0; x < 32; x++) {
|
|
||||||
uint8_t palette = (_vram[addr + 1] >> 2) & 0x07;
|
uint8_t palette = (_vram[addr + 1] >> 2) & 0x07;
|
||||||
uint16_t tileIndex = ((_vram[addr + 1] & 0x03) << 8) | _vram[addr];
|
uint16_t tileIndex = ((_vram[addr + 1] & 0x03) << 8) | _vram[addr];
|
||||||
bool vMirror = (_vram[addr + 1] & 0x80) != 0;
|
bool vMirror = (_vram[addr + 1] & 0x80) != 0;
|
||||||
bool hMirror = (_vram[addr + 1] & 0x40) != 0;
|
bool hMirror = (_vram[addr + 1] & 0x40) != 0;
|
||||||
|
|
||||||
uint16_t tileStart = chrAddr + tileIndex * 8 * bpp;
|
uint16_t tileStart = chrAddr + tileIndex * 8 * bpp;
|
||||||
for(int i = 0; i < 8; i++) {
|
uint8_t yOffset = vMirror ? (7 - (_scanline & 0x07)) : (_scanline & 0x07);
|
||||||
uint8_t yOffset = vMirror ? (7 - i) : i;
|
|
||||||
for(int j = 0; j < 8; j++) {
|
|
||||||
uint16_t color = 0;
|
uint16_t color = 0;
|
||||||
uint8_t shift = hMirror ? j : (7 - j);
|
uint8_t shift = hMirror ? (x & 0x07) : (7 - (x & 0x07));
|
||||||
for(int plane = 0; plane < bpp; plane++) {
|
for(int plane = 0; plane < bpp; plane++) {
|
||||||
uint8_t offset = (plane >> 1) * 16;
|
uint8_t offset = (plane >> 1) * 16;
|
||||||
color |= (((_vram[tileStart + i * 2 + offset + (plane & 0x01)] >> shift) & 0x01) << bpp);
|
color |= (((_vram[tileStart + yOffset * 2 + offset + (plane & 0x01)] >> shift) & 0x01) << bpp);
|
||||||
color >>= 1;
|
color >>= 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -253,137 +395,42 @@ void Ppu::RenderTilemap(uint8_t layerIndex, uint8_t bpp)
|
||||||
uint16_t paletteRamOffset = (palette * (1 << bpp) + color) * 2;
|
uint16_t paletteRamOffset = (palette * (1 << bpp) + color) * 2;
|
||||||
uint16_t paletteColor = _cgram[paletteRamOffset] | (_cgram[paletteRamOffset + 1] << 8);
|
uint16_t paletteColor = _cgram[paletteRamOffset] | (_cgram[paletteRamOffset + 1] << 8);
|
||||||
|
|
||||||
uint16_t ¤tPixel = _currentBuffer[(y * 8 + yOffset) * 256 + x * 8 + j];
|
if(forMainScreen) {
|
||||||
if(useColorMath && layerIndex == 0) {
|
_currentBuffer[(_scanline << 8) | x] = paletteColor;
|
||||||
uint8_t halfShift = _colorMathHalveResult ? 1 : 0;
|
_filled[x] = true;
|
||||||
uint16_t r = std::min(((currentPixel & 0x001F) + (paletteColor & 0x001F)) >> halfShift, 0x1F);
|
} else {
|
||||||
uint16_t g = std::min((((currentPixel >> 5) & 0x001F) + ((paletteColor >> 5) & 0x001F)) >> halfShift, 0x1F);
|
_subScreenBuffer[(_scanline << 8) | x] = paletteColor;
|
||||||
uint16_t b = std::min((((currentPixel >> 10) & 0x001F) + ((paletteColor >> 10) & 0x001F)) >> halfShift, 0x1F);
|
_subScreenFilled[x] = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
paletteColor = r | (g << 5) | (b << 10);
|
void Ppu::ApplyColorMath()
|
||||||
}
|
{
|
||||||
currentPixel = paletteColor;
|
bool useColorMath = _colorMathEnabled;// >> layerIndex) & 0x01) != 0;
|
||||||
}
|
if(!useColorMath) {
|
||||||
}
|
return;
|
||||||
}
|
|
||||||
addr+=2;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for(int x = 0; x < 256; x++) {
|
||||||
|
uint16_t &mainPixel = _currentBuffer[(_scanline << 8) | x];
|
||||||
|
uint16_t &subPixel = _subScreenBuffer[(_scanline << 8) | x];
|
||||||
|
|
||||||
|
uint8_t halfShift = _colorMathHalveResult ? 1 : 0;
|
||||||
|
uint16_t r = std::min(((mainPixel & 0x001F) + (subPixel & 0x001F)) >> halfShift, 0x1F);
|
||||||
|
uint16_t g = std::min((((mainPixel >> 5) & 0x001F) + ((subPixel >> 5) & 0x001F)) >> halfShift, 0x1F);
|
||||||
|
uint16_t b = std::min((((mainPixel >> 10) & 0x001F) + ((subPixel >> 10) & 0x001F)) >> halfShift, 0x1F);
|
||||||
|
|
||||||
|
mainPixel = r | (g << 5) | (b << 10);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Ppu::SendFrame()
|
void Ppu::SendFrame()
|
||||||
{
|
{
|
||||||
/*uint16_t bgColor = _cgram[0] | (_cgram[1]);
|
|
||||||
for(int i = 0; i < 256 * 224; i++) {
|
|
||||||
_currentBuffer[i] = bgColor;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch(_bgMode) {
|
|
||||||
case 0:
|
|
||||||
RenderTilemap(3, 2);
|
|
||||||
RenderTilemap(2, 2);
|
|
||||||
RenderTilemap(1, 2);
|
|
||||||
RenderTilemap(0, 2);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 1:
|
|
||||||
RenderTilemap(2, 2);
|
|
||||||
RenderTilemap(1, 4);
|
|
||||||
RenderTilemap(0, 4);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 2:
|
|
||||||
RenderTilemap(1, 4);
|
|
||||||
RenderTilemap(0, 4);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 3:
|
|
||||||
RenderTilemap(1, 4);
|
|
||||||
RenderTilemap(0, 8);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 5:
|
|
||||||
RenderTilemap(1, 2);
|
|
||||||
RenderTilemap(0, 4);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 6:
|
|
||||||
RenderTilemap(0, 8);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
//Draw sprites
|
|
||||||
if(_mainScreenLayers & 0x10) {
|
|
||||||
DrawSprites();
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
_console->GetNotificationManager()->SendNotification(ConsoleNotificationType::PpuFrameDone);
|
_console->GetNotificationManager()->SendNotification(ConsoleNotificationType::PpuFrameDone);
|
||||||
_console->GetVideoDecoder()->UpdateFrame(_currentBuffer, _frameCount);
|
_console->GetVideoDecoder()->UpdateFrame(_currentBuffer, _frameCount);
|
||||||
_currentBuffer = _currentBuffer == _outputBuffers[0] ? _outputBuffers[1] : _outputBuffers[0];
|
_currentBuffer = _currentBuffer == _outputBuffers[0] ? _outputBuffers[1] : _outputBuffers[0];
|
||||||
|
|
||||||
uint16_t bgColor = _cgram[0] | (_cgram[1]);
|
|
||||||
for(int i = 0; i < 256 * 224; i++) {
|
|
||||||
_currentBuffer[i] = bgColor;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Ppu::DrawSprites()
|
|
||||||
{
|
|
||||||
for(int i = 0; i < 512; i += 4) {
|
|
||||||
uint8_t y = _oamRam[i + 1];
|
|
||||||
if(y >= 225) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
int16_t x = _oamRam[i];
|
|
||||||
uint8_t tileRow = (_oamRam[i + 2] & 0xF0) >> 4;
|
|
||||||
uint8_t tileColumn = _oamRam[i + 2] & 0x0F;
|
|
||||||
uint8_t flags = _oamRam[i + 3];
|
|
||||||
|
|
||||||
uint8_t palette = (flags >> 1) & 0x07;
|
|
||||||
bool useSecondTable = (flags & 0x01) != 0;
|
|
||||||
|
|
||||||
//TODO: vertical, horizontal flip, priority
|
|
||||||
|
|
||||||
uint8_t highTableOffset = i >> 4;
|
|
||||||
uint8_t shift = ((i >> 2) & 0x03) << 1;
|
|
||||||
|
|
||||||
uint8_t highTableValue = _oamRam[0x200 | highTableOffset] >> shift;
|
|
||||||
bool negativeX = (highTableValue & 0x01) != 0;
|
|
||||||
uint8_t size = (highTableValue & 0x02) >> 1;
|
|
||||||
|
|
||||||
if(negativeX) {
|
|
||||||
x = -x;
|
|
||||||
}
|
|
||||||
|
|
||||||
for(int rowOffset = 0; rowOffset < _oamSizes[_oamMode][size][1]; rowOffset++) {
|
|
||||||
for(int columnOffset = 0; columnOffset < _oamSizes[_oamMode][size][0]; columnOffset++) {
|
|
||||||
uint8_t column = (tileColumn + columnOffset) & 0x0F;
|
|
||||||
uint8_t row = (tileRow + rowOffset) & 0x0F;
|
|
||||||
uint8_t tileIndex = (row << 4) | column;
|
|
||||||
|
|
||||||
uint16_t tileStart = ((_oamBaseAddress + (tileIndex << 4) + (useSecondTable ? _oamAddressOffset : 0)) & 0x7FFF) << 1;
|
|
||||||
uint16_t bpp = 4;
|
|
||||||
for(int i = 0; i < 8; i++) {
|
|
||||||
for(int j = 0; j < 8; j++) {
|
|
||||||
uint16_t color = 0;
|
|
||||||
for(int plane = 0; plane < bpp; plane++) {
|
|
||||||
uint8_t offset = (plane >> 1) * 16;
|
|
||||||
color |= (((_vram[tileStart + i * 2 + offset + (plane & 0x01)] >> (7 - j)) & 0x01) << bpp);
|
|
||||||
color >>= 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(color != 0) {
|
|
||||||
uint16_t paletteRamOffset = 256 + ((palette * (1 << bpp) + color) * 2);
|
|
||||||
|
|
||||||
uint16_t paletteColor = _cgram[paletteRamOffset] | (_cgram[paletteRamOffset + 1] << 8);
|
|
||||||
_currentBuffer[(y + i + rowOffset * 8) * 256 + x + j + columnOffset * 8] = paletteColor;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t* Ppu::GetVideoRam()
|
uint8_t* Ppu::GetVideoRam()
|
||||||
|
@ -449,9 +496,7 @@ void Ppu::Write(uint32_t addr, uint8_t value)
|
||||||
|
|
||||||
case 0x2105:
|
case 0x2105:
|
||||||
_bgMode = value & 0x07;
|
_bgMode = value & 0x07;
|
||||||
|
_mode1Bg3Priority = (value & 0x08) != 0;
|
||||||
//TODO
|
|
||||||
//_mode1Bg3Priority = (value & 0x08) != 0;
|
|
||||||
|
|
||||||
_layerConfig[0].LargeTiles = (value & 0x10) != 0;
|
_layerConfig[0].LargeTiles = (value & 0x10) != 0;
|
||||||
_layerConfig[1].LargeTiles = (value & 0x20) != 0;
|
_layerConfig[1].LargeTiles = (value & 0x20) != 0;
|
||||||
|
@ -527,6 +572,11 @@ void Ppu::Write(uint32_t addr, uint8_t value)
|
||||||
_mainScreenLayers = value & 0x1F;
|
_mainScreenLayers = value & 0x1F;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case 0x212D:
|
||||||
|
//TS - Subscreen Designation
|
||||||
|
_subScreenLayers = value & 0x1F;
|
||||||
|
break;
|
||||||
|
|
||||||
case 0x2130:
|
case 0x2130:
|
||||||
//CGWSEL - Color Addition Select
|
//CGWSEL - Color Addition Select
|
||||||
_colorMathClipMode = (value >> 6) & 0x03;
|
_colorMathClipMode = (value >> 6) & 0x03;
|
||||||
|
|
22
Core/Ppu.h
22
Core/Ppu.h
|
@ -32,8 +32,10 @@ private:
|
||||||
uint32_t _frameCount = 0;
|
uint32_t _frameCount = 0;
|
||||||
|
|
||||||
uint8_t _bgMode = 0;
|
uint8_t _bgMode = 0;
|
||||||
|
bool _mode1Bg3Priority = false;
|
||||||
|
|
||||||
uint8_t _mainScreenLayers = 0;
|
uint8_t _mainScreenLayers = 0;
|
||||||
|
uint8_t _subScreenLayers = 0;
|
||||||
LayerConfig _layerConfig[4];
|
LayerConfig _layerConfig[4];
|
||||||
|
|
||||||
uint8_t *_vram;
|
uint8_t *_vram;
|
||||||
|
@ -46,8 +48,12 @@ private:
|
||||||
uint8_t _cgram[Ppu::CgRamSize];
|
uint8_t _cgram[Ppu::CgRamSize];
|
||||||
|
|
||||||
uint16_t *_outputBuffers[2];
|
uint16_t *_outputBuffers[2];
|
||||||
|
bool _filled[256];
|
||||||
uint16_t *_currentBuffer;
|
uint16_t *_currentBuffer;
|
||||||
|
|
||||||
|
bool _subScreenFilled[256];
|
||||||
|
uint16_t *_subScreenBuffer;
|
||||||
|
|
||||||
uint8_t _oamMode = 0;
|
uint8_t _oamMode = 0;
|
||||||
uint16_t _oamBaseAddress = 0;
|
uint16_t _oamBaseAddress = 0;
|
||||||
uint16_t _oamAddressOffset = 0;
|
uint16_t _oamAddressOffset = 0;
|
||||||
|
@ -68,9 +74,19 @@ private:
|
||||||
bool _colorMathSubstractMode = false;
|
bool _colorMathSubstractMode = false;
|
||||||
bool _colorMathHalveResult = false;
|
bool _colorMathHalveResult = false;
|
||||||
|
|
||||||
void RenderTilemap(uint8_t layerIndex, uint8_t bpp);
|
template<bool forMainScreen>
|
||||||
|
void RenderBgColor();
|
||||||
|
|
||||||
|
template<uint8_t layerIndex, uint8_t bpp, bool processHighPriority, bool forMainScreen>
|
||||||
|
void RenderTilemap();
|
||||||
|
|
||||||
|
template<uint8_t priority, bool forMainScreen>
|
||||||
void DrawSprites();
|
void DrawSprites();
|
||||||
|
|
||||||
|
void RenderScanline();
|
||||||
|
void ApplyColorMath();
|
||||||
|
void SendFrame();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Ppu(shared_ptr<Console> console);
|
Ppu(shared_ptr<Console> console);
|
||||||
~Ppu();
|
~Ppu();
|
||||||
|
@ -80,10 +96,6 @@ public:
|
||||||
|
|
||||||
void Exec();
|
void Exec();
|
||||||
|
|
||||||
void RenderScanline();
|
|
||||||
|
|
||||||
void SendFrame();
|
|
||||||
|
|
||||||
uint8_t* GetVideoRam();
|
uint8_t* GetVideoRam();
|
||||||
uint8_t* GetCgRam();
|
uint8_t* GetCgRam();
|
||||||
uint8_t* GetSpriteRam();
|
uint8_t* GetSpriteRam();
|
||||||
|
|
Loading…
Add table
Reference in a new issue