2018-07-02 14:49:19 -04:00
# include "stdafx.h"
# include "HdPpu.h"
# include "CPU.h"
# include "Console.h"
# include "HdNesPack.h"
# include "VideoDecoder.h"
# include "RewindManager.h"
# include "HdPackConditions.h"
# include "NotificationManager.h"
# include "BaseMapper.h"
# include "MemoryManager.h"
void HdPpu : : DrawPixel ( )
{
uint16_t bufferOffset = ( _scanline < < 8 ) + _cycle - 1 ;
uint16_t & pixel = _currentOutputBuffer [ bufferOffset ] ;
_lastSprite = nullptr ;
Add sprite frame range condition
A new condition named "spriteFrameRange" is added. It works like frameRange except it follows frame counters assigned to each sprite. Frame counter picks up the nearest frame counter within 6x6 pixels from the last frame and resets if graphics, palette, bg priority or orientation has changed. The condition can by used by sprite tiles only. For example:
<condition>myCondition,spriteFrameRange,301,60
[myCondition]<tile>0,1001,FF0F3600,8,0,1,N
2021-04-15 19:54:01 +08:00
//init sprite frame ranges at screen start
if ( bufferOffset = = 0 ) {
uint8_t spriteCnt = ( _flags . LargeSprites ? 128 : 64 ) ;
for ( int i = 0 ; i < spriteCnt ; i + + ) {
_spriteFrameRanges [ i ] . lastUpdated = _spriteFrameRanges [ i ] . updated ;
if ( _spriteFrameRanges [ i ] . updated ) {
//copy last frame sprite data
memcpy ( & ( _spriteFrameRanges [ i ] . last ) , & ( _spriteFrameRanges [ i ] . current ) , sizeof ( _spriteFrameRanges [ i ] . current ) ) ;
_spriteFrameRanges [ i ] . updated = false ;
_spriteFrameRanges [ i ] . lastStartFrameNumber = _spriteFrameRanges [ i ] . startFrameNumber ;
}
}
}
2018-07-02 14:49:19 -04:00
if ( IsRenderingEnabled ( ) | | ( ( _state . VideoRamAddr & 0x3F00 ) ! = 0x3F00 ) ) {
bool isChrRam = ! _console - > GetMapper ( ) - > HasChrRom ( ) ;
BaseMapper * mapper = _console - > GetMapper ( ) ;
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 = _info - > ScreenTiles [ bufferOffset ] ;
tileInfo . Grayscale = _paletteRamMask = = 0x30 ;
tileInfo . EmphasisBits = _intensifyColorBits > > 6 ;
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 ) ;
}
tileInfo . XScroll = _state . XScroll ;
tileInfo . TmpVideoRamAddr = _state . TmpVideoRamAddr ;
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 ) {
2018-09-07 21:30:00 -04:00
mapper - > CopyChrTile ( sprite . AbsoluteTileAddr & 0xFFFFFFF0 , tileInfo . Sprite [ j ] . TileData ) ;
2018-07-02 14:49:19 -04:00
}
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 ) ;
}
2021-08-11 09:52:55 +08:00
tileInfo . Sprite [ j ] . PaletteOffset = sprite . PaletteOffset ;
2018-07-02 14:49:19 -04:00
tileInfo . Sprite [ j ] . PpuBackgroundColor = tileInfo . Tile . PpuBackgroundColor ;
tileInfo . Sprite [ j ] . BgColorIndex = tileInfo . Tile . BgColorIndex ;
Add sprite frame range condition
A new condition named "spriteFrameRange" is added. It works like frameRange except it follows frame counters assigned to each sprite. Frame counter picks up the nearest frame counter within 6x6 pixels from the last frame and resets if graphics, palette, bg priority or orientation has changed. The condition can by used by sprite tiles only. For example:
<condition>myCondition,spriteFrameRange,301,60
[myCondition]<tile>0,1001,FF0F3600,8,0,1,N
2021-04-15 19:54:01 +08:00
tileInfo . Sprite [ j ] . OAMIndex = ( sprite . OffsetY > = 8 ? sprite . OAMIndex + 64 : sprite . OAMIndex ) ;
if ( ! _spriteFrameRanges [ tileInfo . Sprite [ j ] . OAMIndex ] . updated ) {
//fill the current frame sprite
if ( isChrRam ) {
memcpy ( _spriteFrameRanges [ tileInfo . Sprite [ j ] . OAMIndex ] . current . TileData , tileInfo . Sprite [ j ] . TileData , 16 ) ;
}
else {
_spriteFrameRanges [ tileInfo . Sprite [ j ] . OAMIndex ] . current . TileIndex = tileInfo . Sprite [ j ] . TileIndex ;
}
_spriteFrameRanges [ tileInfo . Sprite [ j ] . OAMIndex ] . current . PaletteColors = tileInfo . Sprite [ j ] . PaletteColors ;
_spriteFrameRanges [ tileInfo . Sprite [ j ] . OAMIndex ] . current . HorizontalMirroring = tileInfo . Sprite [ j ] . HorizontalMirroring ;
_spriteFrameRanges [ tileInfo . Sprite [ j ] . OAMIndex ] . current . VerticalMirroring = tileInfo . Sprite [ j ] . VerticalMirroring ;
_spriteFrameRanges [ tileInfo . Sprite [ j ] . OAMIndex ] . current . BackgroundPriority = tileInfo . Sprite [ j ] . BackgroundPriority ;
_spriteFrameRanges [ tileInfo . Sprite [ j ] . OAMIndex ] . current . ScreenX = sprite . SpriteX ;
_spriteFrameRanges [ tileInfo . Sprite [ j ] . OAMIndex ] . current . ScreenY = _scanline - tileInfo . Sprite [ j ] . OffsetY ;
_spriteFrameRanges [ tileInfo . Sprite [ j ] . OAMIndex ] . updated = true ;
}
2018-07-02 14:49:19 -04:00
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 ) {
2018-09-07 21:30:00 -04:00
mapper - > CopyChrTile ( lastTile - > AbsoluteTileAddr & 0xFFFFFFF0 , tileInfo . Tile . TileData ) ;
2018-07-02 14:49:19 -04:00
}
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 ;
}
Add sprite frame range condition
A new condition named "spriteFrameRange" is added. It works like frameRange except it follows frame counters assigned to each sprite. Frame counter picks up the nearest frame counter within 6x6 pixels from the last frame and resets if graphics, palette, bg priority or orientation has changed. The condition can by used by sprite tiles only. For example:
<condition>myCondition,spriteFrameRange,301,60
[myCondition]<tile>0,1001,FF0F3600,8,0,1,N
2021-04-15 19:54:01 +08:00
//match sprite frame range at screen end
if ( bufferOffset = = PixelCount - 1 ) {
uint16_t distance ;
uint16_t newDistance ;
uint16_t newDistanceX ;
uint16_t newDistanceY ;
uint8_t spriteCnt = ( _flags . LargeSprites ? 128 : 64 ) ;
for ( int i = 0 ; i < spriteCnt ; i + + ) {
if ( _spriteFrameRanges [ i ] . updated ) {
distance = 13 ;
_spriteFrameRanges [ i ] . startFrameNumber = _frameCount ;
for ( int j = 0 ; j < spriteCnt ; j + + ) {
if ( _spriteFrameRanges [ j ] . lastUpdated ) {
newDistanceX = abs ( _spriteFrameRanges [ i ] . current . ScreenX - _spriteFrameRanges [ j ] . last . ScreenX ) ;
newDistanceY = abs ( _spriteFrameRanges [ i ] . current . ScreenY - _spriteFrameRanges [ j ] . last . ScreenY ) ;
newDistance = newDistanceX + newDistanceY ;
if ( newDistance < distance & & newDistanceX < = 6 & & newDistanceY < = 6 ) {
//check for matches
bool compareResult = false ;
if ( _spriteFrameRanges [ i ] . current . BackgroundPriority = = _spriteFrameRanges [ j ] . last . BackgroundPriority
& & _spriteFrameRanges [ i ] . current . HorizontalMirroring = = _spriteFrameRanges [ j ] . last . HorizontalMirroring
& & _spriteFrameRanges [ i ] . current . VerticalMirroring = = _spriteFrameRanges [ j ] . last . VerticalMirroring
& & _spriteFrameRanges [ i ] . current . PaletteColors = = _spriteFrameRanges [ j ] . last . PaletteColors
) {
if ( isChrRam ) {
compareResult = ( memcmp ( _spriteFrameRanges [ i ] . current . TileData , _spriteFrameRanges [ j ] . last . TileData , 16 ) = = 0 ) ;
}
else {
compareResult = ( _spriteFrameRanges [ i ] . current . TileIndex = = _spriteFrameRanges [ j ] . last . TileIndex ) ;
}
}
if ( compareResult ) {
_spriteFrameRanges [ i ] . startFrameNumber = _spriteFrameRanges [ j ] . lastStartFrameNumber ;
}
distance = newDistance ;
}
}
}
}
}
}
2018-07-02 14:49:19 -04:00
} 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 ;
_info - > ScreenTiles [ bufferOffset ] . Tile . TileIndex = HdPpuTileInfo : : NoTile ;
_info - > ScreenTiles [ bufferOffset ] . SpriteCount = 0 ;
}
}
HdPpu : : HdPpu ( shared_ptr < Console > console , HdPackData * hdData ) : PPU ( console )
{
_hdData = hdData ;
2018-09-13 20:58:35 -04:00
if ( _hdData ) {
_version = _hdData - > Version ;
bool isChrRamGame = ! console - > GetMapper ( ) - > HasChrRom ( ) ;
_screenInfo [ 0 ] = new HdScreenInfo ( isChrRamGame ) ;
_screenInfo [ 1 ] = new HdScreenInfo ( isChrRamGame ) ;
_info = _screenInfo [ 0 ] ;
}
2018-07-02 14:49:19 -04:00
}
HdPpu : : ~ HdPpu ( )
{
2018-09-13 20:58:35 -04:00
if ( _hdData ) {
delete _screenInfo [ 0 ] ;
delete _screenInfo [ 1 ] ;
}
2018-07-02 14:49:19 -04:00
}
void HdPpu : : SendFrame ( )
{
_console - > GetNotificationManager ( ) - > SendNotification ( ConsoleNotificationType : : PpuFrameDone , _currentOutputBuffer ) ;
_info - > FrameNumber = _frameCount ;
Add sprite frame range condition
A new condition named "spriteFrameRange" is added. It works like frameRange except it follows frame counters assigned to each sprite. Frame counter picks up the nearest frame counter within 6x6 pixels from the last frame and resets if graphics, palette, bg priority or orientation has changed. The condition can by used by sprite tiles only. For example:
<condition>myCondition,spriteFrameRange,301,60
[myCondition]<tile>0,1001,FF0F3600,8,0,1,N
2021-04-15 19:54:01 +08:00
_info - > spriteFrameRanges = _spriteFrameRanges ;
2018-07-02 14:49:19 -04:00
_info - > WatchedAddressValues . clear ( ) ;
for ( uint32_t address : _hdData - > WatchedMemoryAddresses ) {
if ( address & HdPackBaseMemoryCondition : : PpuMemoryMarker ) {
if ( ( address & 0x3FFF ) > = 0x3F00 ) {
_info - > WatchedAddressValues [ address ] = ReadPaletteRAM ( address ) ;
} else {
_info - > WatchedAddressValues [ address ] = _console - > GetMapper ( ) - > DebugReadVRAM ( address & 0x3FFF , true ) ;
}
} else {
_info - > WatchedAddressValues [ address ] = _console - > GetMemoryManager ( ) - > DebugRead ( address ) ;
}
}
# ifdef LIBRETRO
_console - > GetVideoDecoder ( ) - > UpdateFrameSync ( _currentOutputBuffer , _info ) ;
# else
if ( _console - > GetRewindManager ( ) - > IsRewinding ( ) ) {
_console - > GetVideoDecoder ( ) - > UpdateFrameSync ( _currentOutputBuffer , _info ) ;
} else {
_console - > GetVideoDecoder ( ) - > UpdateFrame ( _currentOutputBuffer , _info ) ;
}
_currentOutputBuffer = ( _currentOutputBuffer = = _outputBuffers [ 0 ] ) ? _outputBuffers [ 1 ] : _outputBuffers [ 0 ] ;
_info = ( _info = = _screenInfo [ 0 ] ) ? _screenInfo [ 1 ] : _screenInfo [ 0 ] ;
# endif
}