added ppu sprite rendering
This commit is contained in:
parent
a4e4a16eaa
commit
024e439c24
|
@ -16,7 +16,7 @@ Bus::Bus(Screen* screen) :
|
||||||
palettes = std::vector<Byte>(0x20, 0);
|
palettes = std::vector<Byte>(0x20, 0);
|
||||||
|
|
||||||
LOG_CORE_INFO("Inserting cartridge");
|
LOG_CORE_INFO("Inserting cartridge");
|
||||||
cartridge.Load("roms/mario.nes");
|
cartridge.Load("roms/donkeykong.nes");
|
||||||
|
|
||||||
LOG_CORE_INFO("Powering up CPU");
|
LOG_CORE_INFO("Powering up CPU");
|
||||||
cpu.Powerup();
|
cpu.Powerup();
|
||||||
|
@ -82,7 +82,7 @@ void Bus::DMATick()
|
||||||
|
|
||||||
if (DMALatch != 0)
|
if (DMALatch != 0)
|
||||||
{
|
{
|
||||||
Byte data = ReadCPU(((Word)DMAPage << 8) | (0xFF - DMACyclesLeft));
|
Byte data = ReadCPU(((Word)DMAPage << 8) | (0x100 - DMACyclesLeft));
|
||||||
ppu.WriteRegister(0x2004, data);
|
ppu.WriteRegister(0x2004, data);
|
||||||
|
|
||||||
DMACyclesLeft--;
|
DMACyclesLeft--;
|
||||||
|
@ -214,7 +214,7 @@ void Bus::WriteCPU(Word addr, Byte val)
|
||||||
{
|
{
|
||||||
case 0x4014:
|
case 0x4014:
|
||||||
DMAPage = val;
|
DMAPage = val;
|
||||||
DMACyclesLeft = 0xFF;
|
DMACyclesLeft = 0x100;
|
||||||
preDMACycles = 1 + (cpu.GetTotalCycles() % 2);
|
preDMACycles = 1 + (cpu.GetTotalCycles() % 2);
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
|
|
@ -98,7 +98,7 @@ private:
|
||||||
ControllerPort controllerPort;
|
ControllerPort controllerPort;
|
||||||
|
|
||||||
Byte preDMACycles = 0;
|
Byte preDMACycles = 0;
|
||||||
Byte DMACyclesLeft = 0;
|
Word DMACyclesLeft = 0;
|
||||||
Byte DMAPage = 0;
|
Byte DMAPage = 0;
|
||||||
Byte DMALatch = 0;
|
Byte DMALatch = 0;
|
||||||
|
|
||||||
|
|
121
src/PPU.cpp
121
src/PPU.cpp
|
@ -154,6 +154,14 @@ void PPU::Tick()
|
||||||
ppustatus.Flag.SpriteZeroHit = 0;
|
ppustatus.Flag.SpriteZeroHit = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (cycleType == CycleType::Fetching || cycleType == CycleType::PreFetching)
|
||||||
|
{
|
||||||
|
loTile.Raw <<= 1;
|
||||||
|
hiTile.Raw <<= 1;
|
||||||
|
loAttribute.Raw <<= 1;
|
||||||
|
hiAttribute.Raw <<= 1;
|
||||||
|
}
|
||||||
|
|
||||||
// Need to render
|
// Need to render
|
||||||
if (scanlineType == ScanlineType::Visible || scanlineType == ScanlineType::PreRender)
|
if (scanlineType == ScanlineType::Visible || scanlineType == ScanlineType::PreRender)
|
||||||
{
|
{
|
||||||
|
@ -206,14 +214,6 @@ void PPU::Tick()
|
||||||
Color pixel = MultiplexPixel(bgPixel, spritePixel);
|
Color pixel = MultiplexPixel(bgPixel, spritePixel);
|
||||||
screen->SetPixel(x, y, pixel);
|
screen->SetPixel(x, y, pixel);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cycleType == CycleType::Fetching || cycleType == CycleType::PreFetching)
|
|
||||||
{
|
|
||||||
loTile.Raw <<= 1;
|
|
||||||
hiTile.Raw <<= 1;
|
|
||||||
loAttribute.Raw <<= 1;
|
|
||||||
hiAttribute.Raw <<= 1;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Byte PPU::ReadRegister(Byte id)
|
Byte PPU::ReadRegister(Byte id)
|
||||||
|
@ -512,14 +512,14 @@ void PPU::EvaluateSprites()
|
||||||
// Find free slot
|
// Find free slot
|
||||||
secondaryOAM[freeSecondaryOAMSlot] = spriteYCoord;
|
secondaryOAM[freeSecondaryOAMSlot] = spriteYCoord;
|
||||||
Word diff = y - spriteYCoord;
|
Word diff = y - spriteYCoord;
|
||||||
if (diff == 0x6)
|
if (diff < 8u + ppuctrl.Flag.SpriteSize * 8u) // Choose between 8x8 and 8x16 mode
|
||||||
volatile int dkjhfdjf = 32;
|
|
||||||
if (y - spriteYCoord < 8 + ppuctrl.Flag.SpriteSize * 8) // Choose between 8x8 and 8x16 mode
|
|
||||||
{
|
{
|
||||||
secondaryOAM[freeSecondaryOAMSlot + 1] = ReadOAM(oamaddr + 4 * n + 1);
|
secondaryOAM[freeSecondaryOAMSlot + 1] = ReadOAM(oamaddr + 4 * n + 1);
|
||||||
secondaryOAM[freeSecondaryOAMSlot + 2] = ReadOAM(oamaddr + 4 * n + 2);
|
secondaryOAM[freeSecondaryOAMSlot + 2] = ReadOAM(oamaddr + 4 * n + 2);
|
||||||
secondaryOAM[freeSecondaryOAMSlot + 3] = ReadOAM(oamaddr + 4 * n + 3);
|
secondaryOAM[freeSecondaryOAMSlot + 3] = ReadOAM(oamaddr + 4 * n + 3);
|
||||||
|
|
||||||
|
sprites[freeSecondaryOAMSlot >> 2].OAMPosition = n >> 4;
|
||||||
|
|
||||||
freeSecondaryOAMSlot += 4;
|
freeSecondaryOAMSlot += 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -552,6 +552,8 @@ void PPU::EvaluateSprites()
|
||||||
case FetchingPhase::NametableByte: // Fetch garbage
|
case FetchingPhase::NametableByte: // Fetch garbage
|
||||||
nametableByte = Read(0x2000 | (current.Raw & 0x0FFF));
|
nametableByte = Read(0x2000 | (current.Raw & 0x0FFF));
|
||||||
sprites[currentlyEvaluatedSprite].Counter = secondaryOAM[4 * currentlyEvaluatedSprite + 3];
|
sprites[currentlyEvaluatedSprite].Counter = secondaryOAM[4 * currentlyEvaluatedSprite + 3];
|
||||||
|
if (sprites[currentlyEvaluatedSprite].Counter == 0x00)
|
||||||
|
volatile int djf = 3;
|
||||||
sprites[currentlyEvaluatedSprite].FineX = 0;
|
sprites[currentlyEvaluatedSprite].FineX = 0;
|
||||||
|
|
||||||
fetchPhase = FetchingPhase::AttributeTableByte;
|
fetchPhase = FetchingPhase::AttributeTableByte;
|
||||||
|
@ -559,7 +561,7 @@ void PPU::EvaluateSprites()
|
||||||
|
|
||||||
case FetchingPhase::AttributeTableByte: // Fetch garbage
|
case FetchingPhase::AttributeTableByte: // Fetch garbage
|
||||||
attributeTableByte = Read(0x23C0 | (current.Raw & 0x0C00) | ((current.CoarseY >> 2) << 3) | (current.CoarseX >> 2));
|
attributeTableByte = Read(0x23C0 | (current.Raw & 0x0C00) | ((current.CoarseY >> 2) << 3) | (current.CoarseX >> 2));
|
||||||
sprites[currentlyEvaluatedSprite].Latch = secondaryOAM[4 * currentlyEvaluatedSprite + 2];
|
sprites[currentlyEvaluatedSprite].Latch.Raw = secondaryOAM[4 * currentlyEvaluatedSprite + 2];
|
||||||
|
|
||||||
fetchPhase = FetchingPhase::PatternTableLo;
|
fetchPhase = FetchingPhase::PatternTableLo;
|
||||||
break;
|
break;
|
||||||
|
@ -567,6 +569,9 @@ void PPU::EvaluateSprites()
|
||||||
case FetchingPhase::PatternTableLo:
|
case FetchingPhase::PatternTableLo:
|
||||||
{
|
{
|
||||||
Word spriteFineY = y - secondaryOAM[4 * currentlyEvaluatedSprite];
|
Word spriteFineY = y - secondaryOAM[4 * currentlyEvaluatedSprite];
|
||||||
|
if (sprites[currentlyEvaluatedSprite].Latch.FlipVertically)
|
||||||
|
spriteFineY = 7 - spriteFineY;
|
||||||
|
|
||||||
Word tileNumber = secondaryOAM[4 * currentlyEvaluatedSprite + 1] + (spriteFineY >> 3);
|
Word tileNumber = secondaryOAM[4 * currentlyEvaluatedSprite + 1] + (spriteFineY >> 3);
|
||||||
|
|
||||||
sprites[currentlyEvaluatedSprite].Lo = Read((((Word)ppuctrl.Flag.SpritePatternTableAddr << 12) | (tileNumber << 4)) + spriteFineY);
|
sprites[currentlyEvaluatedSprite].Lo = Read((((Word)ppuctrl.Flag.SpritePatternTableAddr << 12) | (tileNumber << 4)) + spriteFineY);
|
||||||
|
@ -577,12 +582,12 @@ void PPU::EvaluateSprites()
|
||||||
case FetchingPhase::PatternTableHi:
|
case FetchingPhase::PatternTableHi:
|
||||||
{
|
{
|
||||||
Word spriteFineY = y - secondaryOAM[4 * currentlyEvaluatedSprite];
|
Word spriteFineY = y - secondaryOAM[4 * currentlyEvaluatedSprite];
|
||||||
|
if (sprites[currentlyEvaluatedSprite].Latch.FlipVertically)
|
||||||
|
spriteFineY = 7 - spriteFineY;
|
||||||
|
|
||||||
Byte tileNumber = secondaryOAM[4 * currentlyEvaluatedSprite + 1] + (spriteFineY >> 3);
|
Byte tileNumber = secondaryOAM[4 * currentlyEvaluatedSprite + 1] + (spriteFineY >> 3);
|
||||||
|
|
||||||
sprites[currentlyEvaluatedSprite].Hi = Read((((Word)ppuctrl.Flag.SpritePatternTableAddr << 12) | (tileNumber << 4)) + 8 + spriteFineY);
|
sprites[currentlyEvaluatedSprite].Hi = Read((((Word)ppuctrl.Flag.SpritePatternTableAddr << 12) | (tileNumber << 4)) + 8 + spriteFineY);
|
||||||
|
|
||||||
if (sprites[currentlyEvaluatedSprite].Hi != 0x00 && sprites[currentlyEvaluatedSprite].Counter == 0x88)
|
|
||||||
volatile int dkjf = 3;
|
|
||||||
|
|
||||||
if (currentlyEvaluatedSprite * 4 >= freeSecondaryOAMSlot)
|
if (currentlyEvaluatedSprite * 4 >= freeSecondaryOAMSlot)
|
||||||
{
|
{
|
||||||
|
@ -627,6 +632,51 @@ Pixel PPU::GetBackgroundPixel()
|
||||||
|
|
||||||
Pixel PPU::GetSpritePixel()
|
Pixel PPU::GetSpritePixel()
|
||||||
{
|
{
|
||||||
|
Pixel returnValue{ 0 };
|
||||||
|
returnValue.color = 0x00;
|
||||||
|
returnValue.palette = 4;
|
||||||
|
returnValue.priority = 1;
|
||||||
|
|
||||||
|
if (!ppumask.Flag.ShowSprites)
|
||||||
|
return returnValue;
|
||||||
|
|
||||||
|
for (Sprite& sprite : sprites)
|
||||||
|
{
|
||||||
|
// Sprite is inacitve
|
||||||
|
if (sprite.Counter != 0 || sprite.FineX >= 8)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// If sprite is active, determine the current pixel
|
||||||
|
|
||||||
|
Byte mask = 0x00;
|
||||||
|
|
||||||
|
if (sprite.Latch.FlipHorizontally)
|
||||||
|
mask = 0x1 << sprite.FineX;
|
||||||
|
else
|
||||||
|
mask = 0x80 >> sprite.FineX;
|
||||||
|
|
||||||
|
Byte loBit = ((sprite.Lo & mask) != 0x00);
|
||||||
|
Byte hiBit = ((sprite.Hi & mask) != 0x00);
|
||||||
|
|
||||||
|
uint8_t color = (hiBit << 1) | loBit;
|
||||||
|
if (color == 0x00)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
uint8_t palette = 4 + sprite.Latch.Palette;
|
||||||
|
if (color == 0x00)
|
||||||
|
palette = 0x00;
|
||||||
|
|
||||||
|
if (x < 5)
|
||||||
|
volatile int djfk = 3;
|
||||||
|
|
||||||
|
returnValue.color = color;
|
||||||
|
returnValue.palette = palette;
|
||||||
|
returnValue.priority = sprite.Latch.Priority;
|
||||||
|
returnValue.isZeroSprite = (sprite.OAMPosition == 0x00);
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
for (Sprite& sprite : sprites)
|
for (Sprite& sprite : sprites)
|
||||||
{
|
{
|
||||||
if (sprite.Counter != 0)
|
if (sprite.Counter != 0)
|
||||||
|
@ -640,47 +690,6 @@ Pixel PPU::GetSpritePixel()
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Pixel returnValue{ 0 };
|
|
||||||
returnValue.color = 0x00;
|
|
||||||
returnValue.palette = 4;
|
|
||||||
returnValue.priority = 1;
|
|
||||||
|
|
||||||
if (!ppumask.Flag.ShowSprites)
|
|
||||||
return returnValue;
|
|
||||||
|
|
||||||
bool firstIteration = true;
|
|
||||||
for (Sprite& sprite : sprites)
|
|
||||||
{
|
|
||||||
// Sprite is inacitve
|
|
||||||
if (sprite.Counter != 0 || sprite.FineX >= 8)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
// If sprite is active, determine the current pixel
|
|
||||||
Byte loBit = (sprite.Lo & 0x80) >> 7;
|
|
||||||
Byte hiBit = (sprite.Hi & 0x80) >> 7;
|
|
||||||
|
|
||||||
uint8_t color = (hiBit << 1) | loBit;
|
|
||||||
if (color == 0x00)
|
|
||||||
{
|
|
||||||
firstIteration = false;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint8_t palette = 4 + (sprite.Latch & 0x3);
|
|
||||||
if (color == 0x00)
|
|
||||||
palette = 0x00;
|
|
||||||
|
|
||||||
sprite.Lo <<= 1;
|
|
||||||
sprite.Hi <<= 1;
|
|
||||||
|
|
||||||
returnValue.color = color;
|
|
||||||
returnValue.palette = palette;
|
|
||||||
returnValue.priority = (sprite.Latch >> 5) & 0x1;
|
|
||||||
returnValue.isZeroSprite = firstIteration;
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
return returnValue;
|
return returnValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
15
src/PPU.hpp
15
src/PPU.hpp
|
@ -57,8 +57,21 @@ union ShiftRegister
|
||||||
|
|
||||||
struct Sprite
|
struct Sprite
|
||||||
{
|
{
|
||||||
|
Byte OAMPosition;
|
||||||
Byte Lo, Hi;
|
Byte Lo, Hi;
|
||||||
Byte Latch;
|
union
|
||||||
|
{
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
Byte Palette : 2;
|
||||||
|
Byte Unimplemented : 3;
|
||||||
|
Byte Priority : 1;
|
||||||
|
Byte FlipHorizontally : 1;
|
||||||
|
Byte FlipVertically : 1;
|
||||||
|
};
|
||||||
|
|
||||||
|
Byte Raw;
|
||||||
|
} Latch;
|
||||||
Byte Counter;
|
Byte Counter;
|
||||||
Byte FineX;
|
Byte FineX;
|
||||||
};
|
};
|
||||||
|
|
|
@ -28,9 +28,6 @@ public:
|
||||||
Byte output = outRegister & 1;
|
Byte output = outRegister & 1;
|
||||||
outRegister >>= 1;
|
outRegister >>= 1;
|
||||||
|
|
||||||
if (output != 0)
|
|
||||||
volatile int jdfk = 3;
|
|
||||||
|
|
||||||
return (output << outPin);
|
return (output << outPin);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue