mirror of
https://github.com/libretro/Mesen.git
synced 2024-12-13 11:57:09 +00:00
167 lines
6.1 KiB
C++
167 lines
6.1 KiB
C++
#pragma once
|
|
#include "stdafx.h"
|
|
#include "PPU.h"
|
|
#include "HdNesPack.h"
|
|
#include "VideoDecoder.h"
|
|
#include "RewindManager.h"
|
|
|
|
class ControlManager;
|
|
|
|
class HdPpu : public PPU
|
|
{
|
|
private:
|
|
HdPpuPixelInfo* _screenTileBuffers[2];
|
|
HdPpuPixelInfo* _screenTiles;
|
|
bool _isChrRam;
|
|
uint32_t _version;
|
|
|
|
protected:
|
|
void DrawPixel()
|
|
{
|
|
uint16_t bufferOffset = (_scanline << 8) + _cycle - 1;
|
|
uint16_t &pixel = _currentOutputBuffer[bufferOffset];
|
|
_lastSprite = nullptr;
|
|
|
|
if(IsRenderingEnabled() || ((_state.VideoRamAddr & 0x3F00) != 0x3F00)) {
|
|
uint32_t color = GetPixelColor();
|
|
pixel = (_paletteRAM[color & 0x03 ? color : 0] & _paletteRamMask) | _intensifyColorBits;
|
|
|
|
TileInfo* lastTile = &((_state.XScroll + ((_cycle - 1) & 0x07) < 8) ? _previousTile : _currentTile);
|
|
uint32_t backgroundColor = 0;
|
|
if(_flags.BackgroundEnabled && _cycle > _minimumDrawBgCycle) {
|
|
backgroundColor = (((_state.LowBitShift << _state.XScroll) & 0x8000) >> 15) | (((_state.HighBitShift << _state.XScroll) & 0x8000) >> 14);
|
|
}
|
|
|
|
HdPpuPixelInfo &tileInfo = _screenTiles[bufferOffset];
|
|
|
|
tileInfo.Tile.PpuBackgroundColor = ReadPaletteRAM(0);
|
|
tileInfo.Tile.BgColorIndex = backgroundColor;
|
|
if(backgroundColor == 0) {
|
|
tileInfo.Tile.BgColor = tileInfo.Tile.PpuBackgroundColor;
|
|
} else {
|
|
tileInfo.Tile.BgColor = ReadPaletteRAM(lastTile->PaletteOffset + backgroundColor);
|
|
}
|
|
|
|
if(_lastSprite && _flags.SpritesEnabled) {
|
|
int j = 0;
|
|
for(uint8_t i = 0; i < _spriteCount; i++) {
|
|
int32_t shift = (int32_t)_cycle - _spriteTiles[i].SpriteX - 1;
|
|
SpriteInfo& sprite = _spriteTiles[i];
|
|
if(shift >= 0 && shift < 8) {
|
|
tileInfo.Sprite[j].TileIndex = sprite.AbsoluteTileAddr / 16;
|
|
if(_isChrRam) {
|
|
_mapper->CopyChrRamTile(sprite.AbsoluteTileAddr & 0xFFFFFFF0, tileInfo.Sprite[j].TileData);
|
|
}
|
|
if(_version >= 100) {
|
|
tileInfo.Sprite[j].PaletteColors = 0xFF000000 | _paletteRAM[sprite.PaletteOffset + 3] | (_paletteRAM[sprite.PaletteOffset + 2] << 8) | (_paletteRAM[sprite.PaletteOffset + 1] << 16);
|
|
} else {
|
|
tileInfo.Sprite[j].PaletteColors = _paletteRAM[sprite.PaletteOffset + 3] | (_paletteRAM[sprite.PaletteOffset + 2] << 8) | (_paletteRAM[sprite.PaletteOffset + 1] << 16);
|
|
}
|
|
if(sprite.OffsetY >= 8) {
|
|
tileInfo.Sprite[j].OffsetY = sprite.OffsetY - 8;
|
|
} else {
|
|
tileInfo.Sprite[j].OffsetY = sprite.OffsetY;
|
|
}
|
|
|
|
|
|
tileInfo.Sprite[j].OffsetX = shift;
|
|
tileInfo.Sprite[j].HorizontalMirroring = sprite.HorizontalMirror;
|
|
tileInfo.Sprite[j].VerticalMirroring = sprite.VerticalMirror;
|
|
tileInfo.Sprite[j].BackgroundPriority = sprite.BackgroundPriority;
|
|
|
|
int32_t shift = (int32_t)_cycle - sprite.SpriteX - 1;
|
|
if(sprite.HorizontalMirror) {
|
|
tileInfo.Sprite[j].SpriteColorIndex = ((sprite.LowByte >> shift) & 0x01) | ((sprite.HighByte >> shift) & 0x01) << 1;
|
|
} else {
|
|
tileInfo.Sprite[j].SpriteColorIndex = ((sprite.LowByte << shift) & 0x80) >> 7 | ((sprite.HighByte << shift) & 0x80) >> 6;
|
|
}
|
|
|
|
if(tileInfo.Sprite[j].SpriteColorIndex == 0) {
|
|
tileInfo.Sprite[j].SpriteColor = ReadPaletteRAM(0);
|
|
} else {
|
|
tileInfo.Sprite[j].SpriteColor = ReadPaletteRAM(sprite.PaletteOffset + tileInfo.Sprite[j].SpriteColorIndex);
|
|
}
|
|
|
|
tileInfo.Sprite[j].PpuBackgroundColor = tileInfo.Tile.PpuBackgroundColor;
|
|
tileInfo.Sprite[j].BgColorIndex = tileInfo.Tile.BgColorIndex;
|
|
|
|
j++;
|
|
if(j >= 4) {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
tileInfo.SpriteCount = j;
|
|
} else {
|
|
tileInfo.SpriteCount = 0;
|
|
}
|
|
|
|
if(_flags.BackgroundEnabled && _cycle > _minimumDrawBgCycle) {
|
|
tileInfo.Tile.TileIndex = lastTile->AbsoluteTileAddr / 16;
|
|
if(_isChrRam) {
|
|
_mapper->CopyChrRamTile(lastTile->AbsoluteTileAddr & 0xFFFFFFF0, tileInfo.Tile.TileData);
|
|
}
|
|
if(_version >= 100) {
|
|
tileInfo.Tile.PaletteColors = _paletteRAM[lastTile->PaletteOffset + 3] | (_paletteRAM[lastTile->PaletteOffset + 2] << 8) | (_paletteRAM[lastTile->PaletteOffset + 1] << 16) | (_paletteRAM[0] << 24);
|
|
} else {
|
|
tileInfo.Tile.PaletteColors = _paletteRAM[lastTile->PaletteOffset + 3] | (_paletteRAM[lastTile->PaletteOffset + 2] << 8) | (_paletteRAM[lastTile->PaletteOffset + 1] << 16);
|
|
}
|
|
tileInfo.Tile.OffsetY = lastTile->OffsetY;
|
|
tileInfo.Tile.OffsetX = (_state.XScroll + ((_cycle - 1) & 0x07)) & 0x07;
|
|
} else {
|
|
tileInfo.Tile.TileIndex = HdPpuTileInfo::NoTile;
|
|
}
|
|
} else {
|
|
//"If the current VRAM address points in the range $3F00-$3FFF during forced blanking, the color indicated by this palette location will be shown on screen instead of the backdrop color."
|
|
pixel = ReadPaletteRAM(_state.VideoRamAddr) | _intensifyColorBits;
|
|
_screenTiles[bufferOffset].Tile.TileIndex = HdPpuTileInfo::NoTile;
|
|
_screenTiles[bufferOffset].SpriteCount = 0;
|
|
}
|
|
}
|
|
|
|
public:
|
|
HdPpu(BaseMapper* mapper, ControlManager* controlManager, uint32_t version) : PPU(mapper, controlManager)
|
|
{
|
|
_isChrRam = !_mapper->HasChrRom();
|
|
_version = version;
|
|
|
|
_screenTileBuffers[0] = new HdPpuPixelInfo[256 * 240];
|
|
_screenTileBuffers[1] = new HdPpuPixelInfo[256 * 240];
|
|
|
|
for(int i = 0; i < 256 * 240; i++) {
|
|
for(int j = 0; j < 2; j++) {
|
|
_screenTileBuffers[j][i].Tile.BackgroundPriority = false;
|
|
_screenTileBuffers[j][i].Tile.IsChrRamTile = _isChrRam;
|
|
_screenTileBuffers[j][i].Tile.HorizontalMirroring = false;
|
|
_screenTileBuffers[j][i].Tile.VerticalMirroring = false;
|
|
|
|
for(int k = 0; k < 4; k++) {
|
|
_screenTileBuffers[j][i].Sprite[k].IsChrRamTile = _isChrRam;
|
|
}
|
|
}
|
|
}
|
|
|
|
_screenTiles = _screenTileBuffers[0];
|
|
|
|
}
|
|
|
|
~HdPpu()
|
|
{
|
|
delete[] _screenTileBuffers[0];
|
|
delete[] _screenTileBuffers[1];
|
|
}
|
|
|
|
void SendFrame()
|
|
{
|
|
MessageManager::SendNotification(ConsoleNotificationType::PpuFrameDone, _currentOutputBuffer);
|
|
|
|
if(RewindManager::IsRewinding()) {
|
|
VideoDecoder::GetInstance()->UpdateFrameSync(_currentOutputBuffer, _screenTiles);
|
|
} else {
|
|
VideoDecoder::GetInstance()->UpdateFrame(_currentOutputBuffer, _screenTiles);
|
|
}
|
|
|
|
_currentOutputBuffer = (_currentOutputBuffer == _outputBuffers[0]) ? _outputBuffers[1] : _outputBuffers[0];
|
|
_screenTiles = (_screenTiles == _screenTileBuffers[0]) ? _screenTileBuffers[1] : _screenTileBuffers[0];
|
|
}
|
|
}; |