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
This commit is contained in:
parent
0f35fdc97c
commit
8e0816807f
8 changed files with 172 additions and 15 deletions
|
@ -90,6 +90,8 @@ struct HdPpuTileInfo : public HdTileKey
|
||||||
uint8_t BgColor;
|
uint8_t BgColor;
|
||||||
uint8_t SpriteColor;
|
uint8_t SpriteColor;
|
||||||
uint8_t PpuBackgroundColor;
|
uint8_t PpuBackgroundColor;
|
||||||
|
|
||||||
|
uint8_t OAMIndex;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct HdPpuPixelInfo
|
struct HdPpuPixelInfo
|
||||||
|
@ -111,11 +113,36 @@ struct HdPpuPixelInfo
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct HdScreenTileInfo : public HdTileKey
|
||||||
|
{
|
||||||
|
int16_t ScreenX;
|
||||||
|
int16_t ScreenY;
|
||||||
|
bool HorizontalMirroring;
|
||||||
|
bool VerticalMirroring;
|
||||||
|
bool BackgroundPriority;
|
||||||
|
bool IsNew;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct HdSpriteFrameRangeInfo
|
||||||
|
{
|
||||||
|
bool lastUpdated;
|
||||||
|
bool updated;
|
||||||
|
HdScreenTileInfo last;
|
||||||
|
HdScreenTileInfo current;
|
||||||
|
uint32_t lastStartFrameNumber;
|
||||||
|
uint32_t startFrameNumber;
|
||||||
|
|
||||||
|
HdSpriteFrameRangeInfo() {
|
||||||
|
updated = false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
struct HdScreenInfo
|
struct HdScreenInfo
|
||||||
{
|
{
|
||||||
HdPpuPixelInfo* ScreenTiles;
|
HdPpuPixelInfo* ScreenTiles;
|
||||||
std::unordered_map<uint32_t, uint8_t> WatchedAddressValues;
|
std::unordered_map<uint32_t, uint8_t> WatchedAddressValues;
|
||||||
uint32_t FrameNumber;
|
uint32_t FrameNumber;
|
||||||
|
HdSpriteFrameRangeInfo* spriteFrameRanges;
|
||||||
|
|
||||||
HdScreenInfo(const HdScreenInfo& that) = delete;
|
HdScreenInfo(const HdScreenInfo& that) = delete;
|
||||||
|
|
||||||
|
@ -390,12 +417,4 @@ enum class HdPackOptions
|
||||||
DontRenderOriginalTiles = 16
|
DontRenderOriginalTiles = 16
|
||||||
};
|
};
|
||||||
|
|
||||||
struct HdScreenTileInfo : public HdTileKey
|
|
||||||
{
|
|
||||||
int16_t ScreenX;
|
|
||||||
int16_t ScreenY;
|
|
||||||
bool HorizontalMirroring;
|
|
||||||
bool VerticalMirroring;
|
|
||||||
bool BackgroundPriority;
|
|
||||||
bool IsNew;
|
|
||||||
};
|
|
||||||
|
|
|
@ -298,3 +298,32 @@ struct HdPackSpriteNearbyCondition : public HdPackBaseTileCondition
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct HdPackSpriteFrameRangeCondition : public HdPackCondition
|
||||||
|
{
|
||||||
|
uint32_t OperandA;
|
||||||
|
uint32_t OperandB;
|
||||||
|
|
||||||
|
string GetConditionName() override { return "spriteFrameRange"; }
|
||||||
|
|
||||||
|
void Initialize(uint32_t operandA, uint32_t operandB)
|
||||||
|
{
|
||||||
|
OperandA = operandA;
|
||||||
|
OperandB = operandB;
|
||||||
|
}
|
||||||
|
|
||||||
|
string ToString() override
|
||||||
|
{
|
||||||
|
stringstream out;
|
||||||
|
out << "<condition>" << Name << "," << GetConditionName() << ",";
|
||||||
|
out << OperandA << ",";
|
||||||
|
out << OperandB;
|
||||||
|
|
||||||
|
return out.str();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool InternalCheckCondition(HdScreenInfo* screenInfo, int x, int y, HdPpuTileInfo* tile) override
|
||||||
|
{
|
||||||
|
return (screenInfo->FrameNumber - screenInfo->spriteFrameRanges[tile->OAMIndex].startFrameNumber) % OperandA >= OperandB;
|
||||||
|
}
|
||||||
|
};
|
|
@ -424,6 +424,8 @@ void HdPackLoader::ProcessConditionTag(vector<string> &tokens, bool createInvert
|
||||||
condition.reset(new HdPackMemoryCheckConstantCondition());
|
condition.reset(new HdPackMemoryCheckConstantCondition());
|
||||||
} else if(tokens[1] == "frameRange") {
|
} else if(tokens[1] == "frameRange") {
|
||||||
condition.reset(new HdPackFrameRangeCondition());
|
condition.reset(new HdPackFrameRangeCondition());
|
||||||
|
} else if(tokens[1] == "spriteFrameRange") {
|
||||||
|
condition.reset(new HdPackSpriteFrameRangeCondition());
|
||||||
} else {
|
} else {
|
||||||
MessageManager::Log("[HDPack] Invalid condition type: " + tokens[1]);
|
MessageManager::Log("[HDPack] Invalid condition type: " + tokens[1]);
|
||||||
return;
|
return;
|
||||||
|
@ -530,6 +532,27 @@ void HdPackLoader::ProcessConditionTag(vector<string> &tokens, bool createInvert
|
||||||
|
|
||||||
((HdPackFrameRangeCondition*)condition.get())->Initialize(operandA, operandB);
|
((HdPackFrameRangeCondition*)condition.get())->Initialize(operandA, operandB);
|
||||||
}
|
}
|
||||||
|
else if (dynamic_cast<HdPackSpriteFrameRangeCondition*>(condition.get())) {
|
||||||
|
checkConstraint(_data->Version >= 101, "[HDPack] This feature requires version 101+ of HD Packs");
|
||||||
|
checkConstraint(tokens.size() >= 4, "[HDPack] Condition tag should contain at least 4 parameters");
|
||||||
|
|
||||||
|
int32_t operandA;
|
||||||
|
int32_t operandB;
|
||||||
|
if (_data->Version == 101) {
|
||||||
|
operandA = HexUtilities::FromHex(tokens[index++]);
|
||||||
|
operandB = HexUtilities::FromHex(tokens[index++]);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
//Version 102+
|
||||||
|
operandA = std::stoi(tokens[index++]);
|
||||||
|
operandB = std::stoi(tokens[index++]);
|
||||||
|
}
|
||||||
|
|
||||||
|
checkConstraint(operandA >= 0 && operandA <= 0xFFFF, "[HDPack] Out of range spriteFrameRange operand");
|
||||||
|
checkConstraint(operandB >= 0 && operandB <= 0xFFFF, "[HDPack] Out of range spriteFrameRange operand");
|
||||||
|
|
||||||
|
((HdPackSpriteFrameRangeCondition*)condition.get())->Initialize(operandA, operandB);
|
||||||
|
}
|
||||||
|
|
||||||
HdPackCondition *cond = condition.get();
|
HdPackCondition *cond = condition.get();
|
||||||
condition.release();
|
condition.release();
|
||||||
|
|
|
@ -16,6 +16,20 @@ void HdPpu::DrawPixel()
|
||||||
uint16_t &pixel = _currentOutputBuffer[bufferOffset];
|
uint16_t &pixel = _currentOutputBuffer[bufferOffset];
|
||||||
_lastSprite = nullptr;
|
_lastSprite = nullptr;
|
||||||
|
|
||||||
|
//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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if(IsRenderingEnabled() || ((_state.VideoRamAddr & 0x3F00) != 0x3F00)) {
|
if(IsRenderingEnabled() || ((_state.VideoRamAddr & 0x3F00) != 0x3F00)) {
|
||||||
bool isChrRam = !_console->GetMapper()->HasChrRom();
|
bool isChrRam = !_console->GetMapper()->HasChrRom();
|
||||||
BaseMapper *mapper = _console->GetMapper();
|
BaseMapper *mapper = _console->GetMapper();
|
||||||
|
@ -85,6 +99,24 @@ void HdPpu::DrawPixel()
|
||||||
|
|
||||||
tileInfo.Sprite[j].PpuBackgroundColor = tileInfo.Tile.PpuBackgroundColor;
|
tileInfo.Sprite[j].PpuBackgroundColor = tileInfo.Tile.PpuBackgroundColor;
|
||||||
tileInfo.Sprite[j].BgColorIndex = tileInfo.Tile.BgColorIndex;
|
tileInfo.Sprite[j].BgColorIndex = tileInfo.Tile.BgColorIndex;
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
j++;
|
j++;
|
||||||
if(j >= 4) {
|
if(j >= 4) {
|
||||||
|
@ -112,6 +144,49 @@ void HdPpu::DrawPixel()
|
||||||
} else {
|
} else {
|
||||||
tileInfo.Tile.TileIndex = HdPpuTileInfo::NoTile;
|
tileInfo.Tile.TileIndex = HdPpuTileInfo::NoTile;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
} else {
|
} 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."
|
//"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;
|
pixel = ReadPaletteRAM(_state.VideoRamAddr) | _intensifyColorBits;
|
||||||
|
@ -147,6 +222,7 @@ void HdPpu::SendFrame()
|
||||||
_console->GetNotificationManager()->SendNotification(ConsoleNotificationType::PpuFrameDone, _currentOutputBuffer);
|
_console->GetNotificationManager()->SendNotification(ConsoleNotificationType::PpuFrameDone, _currentOutputBuffer);
|
||||||
|
|
||||||
_info->FrameNumber = _frameCount;
|
_info->FrameNumber = _frameCount;
|
||||||
|
_info->spriteFrameRanges = _spriteFrameRanges;
|
||||||
_info->WatchedAddressValues.clear();
|
_info->WatchedAddressValues.clear();
|
||||||
for(uint32_t address : _hdData->WatchedMemoryAddresses) {
|
for(uint32_t address : _hdData->WatchedMemoryAddresses) {
|
||||||
if(address & HdPackBaseMemoryCondition::PpuMemoryMarker) {
|
if(address & HdPackBaseMemoryCondition::PpuMemoryMarker) {
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
#include "stdafx.h"
|
#include "stdafx.h"
|
||||||
#include "PPU.h"
|
#include "PPU.h"
|
||||||
|
#include "HdData.h"
|
||||||
|
|
||||||
struct HdScreenInfo;
|
struct HdScreenInfo;
|
||||||
struct HdPackData;
|
struct HdPackData;
|
||||||
|
@ -13,6 +14,7 @@ private:
|
||||||
HdScreenInfo *_screenInfo[2];
|
HdScreenInfo *_screenInfo[2];
|
||||||
HdScreenInfo *_info;
|
HdScreenInfo *_info;
|
||||||
uint32_t _version;
|
uint32_t _version;
|
||||||
|
HdSpriteFrameRangeInfo _spriteFrameRanges[128];
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
HdPackData *_hdData = nullptr;
|
HdPackData *_hdData = nullptr;
|
||||||
|
|
13
Core/PPU.cpp
13
Core/PPU.cpp
|
@ -337,6 +337,7 @@ uint8_t PPU::ReadRAM(uint16_t addr)
|
||||||
uint8_t step = ((_cycle - 257) % 8) > 3 ? 3 : ((_cycle - 257) % 8);
|
uint8_t step = ((_cycle - 257) % 8) > 3 ? 3 : ((_cycle - 257) % 8);
|
||||||
_secondaryOAMAddr = (_cycle - 257) / 8 * 4 + step;
|
_secondaryOAMAddr = (_cycle - 257) / 8 * 4 + step;
|
||||||
_oamCopybuffer = _secondarySpriteRAM[_secondaryOAMAddr];
|
_oamCopybuffer = _secondarySpriteRAM[_secondaryOAMAddr];
|
||||||
|
_oamID = _secondarySpriteRAMLink[_secondaryOAMAddr >> 2];
|
||||||
}
|
}
|
||||||
//Return the value that PPU is currently using for sprite evaluation/rendering
|
//Return the value that PPU is currently using for sprite evaluation/rendering
|
||||||
returnValue = _oamCopybuffer;
|
returnValue = _oamCopybuffer;
|
||||||
|
@ -690,7 +691,7 @@ void PPU::LoadTileInfo()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void PPU::LoadSprite(uint8_t spriteY, uint8_t tileIndex, uint8_t attributes, uint8_t spriteX, bool extraSprite)
|
void PPU::LoadSprite(uint8_t spriteY, uint8_t tileIndex, uint8_t attributes, uint8_t spriteX, bool extraSprite, uint8_t oamID)
|
||||||
{
|
{
|
||||||
bool backgroundPriority = (attributes & 0x20) == 0x20;
|
bool backgroundPriority = (attributes & 0x20) == 0x20;
|
||||||
bool horizontalMirror = (attributes & 0x40) == 0x40;
|
bool horizontalMirror = (attributes & 0x40) == 0x40;
|
||||||
|
@ -730,6 +731,7 @@ void PPU::LoadSprite(uint8_t spriteY, uint8_t tileIndex, uint8_t attributes, uin
|
||||||
info.AbsoluteTileAddr = _console->GetMapper()->ToAbsoluteChrAddress(tileAddr);
|
info.AbsoluteTileAddr = _console->GetMapper()->ToAbsoluteChrAddress(tileAddr);
|
||||||
info.OffsetY = lineOffset;
|
info.OffsetY = lineOffset;
|
||||||
info.SpriteX = spriteX;
|
info.SpriteX = spriteX;
|
||||||
|
info.OAMIndex = oamID;
|
||||||
|
|
||||||
if(_scanline >= 0) {
|
if(_scanline >= 0) {
|
||||||
//Sprites read on prerender scanline are not shown on scanline 0
|
//Sprites read on prerender scanline are not shown on scanline 0
|
||||||
|
@ -788,7 +790,7 @@ void PPU::LoadExtraSprites()
|
||||||
for(uint32_t i = (_lastVisibleSpriteAddr + 4) & 0xFF; i != _firstVisibleSpriteAddr; i = (i + 4) & 0xFF) {
|
for(uint32_t i = (_lastVisibleSpriteAddr + 4) & 0xFF; i != _firstVisibleSpriteAddr; i = (i + 4) & 0xFF) {
|
||||||
uint8_t spriteY = _spriteRAM[i];
|
uint8_t spriteY = _spriteRAM[i];
|
||||||
if(_scanline >= spriteY && _scanline < spriteY + (_flags.LargeSprites ? 16 : 8)) {
|
if(_scanline >= spriteY && _scanline < spriteY + (_flags.LargeSprites ? 16 : 8)) {
|
||||||
LoadSprite(spriteY, _spriteRAM[i + 1], _spriteRAM[i + 2], _spriteRAM[i + 3], true);
|
LoadSprite(spriteY, _spriteRAM[i + 1], _spriteRAM[i + 2], _spriteRAM[i + 3], true, i >> 2);
|
||||||
_spriteCount++;
|
_spriteCount++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -799,7 +801,7 @@ void PPU::LoadExtraSprites()
|
||||||
void PPU::LoadSpriteTileInfo()
|
void PPU::LoadSpriteTileInfo()
|
||||||
{
|
{
|
||||||
uint8_t *spriteAddr = _secondarySpriteRAM + _spriteIndex * 4;
|
uint8_t *spriteAddr = _secondarySpriteRAM + _spriteIndex * 4;
|
||||||
LoadSprite(*spriteAddr, *(spriteAddr+1), *(spriteAddr+2), *(spriteAddr+3), false);
|
LoadSprite(*spriteAddr, *(spriteAddr+1), *(spriteAddr+2), *(spriteAddr+3), false, _secondarySpriteRAMLink[_spriteIndex]);
|
||||||
}
|
}
|
||||||
|
|
||||||
void PPU::ShiftTileRegisters()
|
void PPU::ShiftTileRegisters()
|
||||||
|
@ -1036,12 +1038,14 @@ void PPU::ProcessSpriteEvaluation()
|
||||||
if(_cycle & 0x01) {
|
if(_cycle & 0x01) {
|
||||||
//Read a byte from the primary OAM on odd cycles
|
//Read a byte from the primary OAM on odd cycles
|
||||||
_oamCopybuffer = ReadSpriteRam(_state.SpriteRamAddr);
|
_oamCopybuffer = ReadSpriteRam(_state.SpriteRamAddr);
|
||||||
|
_oamID = _state.SpriteRamAddr >> 2;
|
||||||
} else {
|
} else {
|
||||||
if(_oamCopyDone) {
|
if(_oamCopyDone) {
|
||||||
_spriteAddrH = (_spriteAddrH + 1) & 0x3F;
|
_spriteAddrH = (_spriteAddrH + 1) & 0x3F;
|
||||||
if(_secondaryOAMAddr >= 0x20) {
|
if(_secondaryOAMAddr >= 0x20) {
|
||||||
//"As seen above, a side effect of the OAM write disable signal is to turn writes to the secondary OAM into reads from it."
|
//"As seen above, a side effect of the OAM write disable signal is to turn writes to the secondary OAM into reads from it."
|
||||||
_oamCopybuffer = _secondarySpriteRAM[_secondaryOAMAddr & 0x1F];
|
_oamCopybuffer = _secondarySpriteRAM[_secondaryOAMAddr & 0x1F];
|
||||||
|
_oamID = _secondarySpriteRAMLink[(_secondaryOAMAddr >> 2) & 0x08];
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if(!_spriteInRange && _scanline >= _oamCopybuffer && _scanline < _oamCopybuffer + (_flags.LargeSprites ? 16 : 8)) {
|
if(!_spriteInRange && _scanline >= _oamCopybuffer && _scanline < _oamCopybuffer + (_flags.LargeSprites ? 16 : 8)) {
|
||||||
|
@ -1051,7 +1055,7 @@ void PPU::ProcessSpriteEvaluation()
|
||||||
if(_secondaryOAMAddr < 0x20) {
|
if(_secondaryOAMAddr < 0x20) {
|
||||||
//Copy 1 byte to secondary OAM
|
//Copy 1 byte to secondary OAM
|
||||||
_secondarySpriteRAM[_secondaryOAMAddr] = _oamCopybuffer;
|
_secondarySpriteRAM[_secondaryOAMAddr] = _oamCopybuffer;
|
||||||
|
_secondarySpriteRAMLink[_secondaryOAMAddr >> 2] =_oamID;
|
||||||
if(_spriteInRange) {
|
if(_spriteInRange) {
|
||||||
_spriteAddrL++;
|
_spriteAddrL++;
|
||||||
_secondaryOAMAddr++;
|
_secondaryOAMAddr++;
|
||||||
|
@ -1083,6 +1087,7 @@ void PPU::ProcessSpriteEvaluation()
|
||||||
} else {
|
} else {
|
||||||
//"As seen above, a side effect of the OAM write disable signal is to turn writes to the secondary OAM into reads from it."
|
//"As seen above, a side effect of the OAM write disable signal is to turn writes to the secondary OAM into reads from it."
|
||||||
_oamCopybuffer = _secondarySpriteRAM[_secondaryOAMAddr & 0x1F];
|
_oamCopybuffer = _secondarySpriteRAM[_secondaryOAMAddr & 0x1F];
|
||||||
|
_oamID = _secondarySpriteRAMLink[(_secondaryOAMAddr >> 2) & 0x08];
|
||||||
|
|
||||||
//8 sprites have been found, check next sprite for overflow + emulate PPU bug
|
//8 sprites have been found, check next sprite for overflow + emulate PPU bug
|
||||||
if(_spriteInRange) {
|
if(_spriteInRange) {
|
||||||
|
|
|
@ -44,6 +44,7 @@ class PPU : public IMemoryHandler, public Snapshotable
|
||||||
|
|
||||||
uint8_t _spriteRAM[0x100];
|
uint8_t _spriteRAM[0x100];
|
||||||
uint8_t _secondarySpriteRAM[0x20];
|
uint8_t _secondarySpriteRAM[0x20];
|
||||||
|
uint8_t _secondarySpriteRAMLink[8];
|
||||||
bool _hasSprite[257];
|
bool _hasSprite[257];
|
||||||
|
|
||||||
uint16_t *_currentOutputBuffer;
|
uint16_t *_currentOutputBuffer;
|
||||||
|
@ -90,6 +91,7 @@ class PPU : public IMemoryHandler, public Snapshotable
|
||||||
uint8_t _spriteAddrL;
|
uint8_t _spriteAddrL;
|
||||||
bool _oamCopyDone;
|
bool _oamCopyDone;
|
||||||
uint8_t _overflowBugCounter;
|
uint8_t _overflowBugCounter;
|
||||||
|
uint8_t _oamID;
|
||||||
|
|
||||||
bool _needStateUpdate;
|
bool _needStateUpdate;
|
||||||
bool _renderingEnabled;
|
bool _renderingEnabled;
|
||||||
|
@ -134,7 +136,7 @@ class PPU : public IMemoryHandler, public Snapshotable
|
||||||
void TriggerNmi();
|
void TriggerNmi();
|
||||||
|
|
||||||
void LoadTileInfo();
|
void LoadTileInfo();
|
||||||
void LoadSprite(uint8_t spriteY, uint8_t tileIndex, uint8_t attributes, uint8_t spriteX, bool extraSprite);
|
void LoadSprite(uint8_t spriteY, uint8_t tileIndex, uint8_t attributes, uint8_t spriteX, bool extraSprite, uint8_t oamID);
|
||||||
void LoadSpriteTileInfo();
|
void LoadSpriteTileInfo();
|
||||||
void LoadExtraSprites();
|
void LoadExtraSprites();
|
||||||
__forceinline void ShiftTileRegisters();
|
__forceinline void ShiftTileRegisters();
|
||||||
|
|
|
@ -185,6 +185,7 @@ struct SpriteInfo : TileInfo
|
||||||
uint8_t SpriteX;
|
uint8_t SpriteX;
|
||||||
|
|
||||||
bool VerticalMirror; //used by HD ppu
|
bool VerticalMirror; //used by HD ppu
|
||||||
|
uint8_t OAMIndex; //used by HD ppu
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ApuLengthCounterState
|
struct ApuLengthCounterState
|
||||||
|
|
Loading…
Add table
Reference in a new issue