More PPU BG drawing code
This commit is contained in:
parent
c6f65e5ad2
commit
d07f61b081
@ -20,7 +20,9 @@ add_executable(nes
|
|||||||
src/Mapper/Mapper0.cpp
|
src/Mapper/Mapper0.cpp
|
||||||
src/Mapper/Mapper0.h src/Ppu.cpp src/Ppu.h
|
src/Mapper/Mapper0.h src/Ppu.cpp src/Ppu.h
|
||||||
src/Window.cpp
|
src/Window.cpp
|
||||||
src/Window.h)
|
src/Window.h
|
||||||
|
src/Shifter.cpp
|
||||||
|
src/Shifter.h)
|
||||||
|
|
||||||
find_package(SDL2 CONFIG REQUIRED)
|
find_package(SDL2 CONFIG REQUIRED)
|
||||||
target_link_libraries(nes PRIVATE SDL2::SDL2)
|
target_link_libraries(nes PRIVATE SDL2::SDL2)
|
||||||
138
src/Ppu.cpp
138
src/Ppu.cpp
@ -88,22 +88,39 @@ namespace nes {
|
|||||||
|
|
||||||
// All visible scanlines
|
// All visible scanlines
|
||||||
if (_scanline >= -1 && _scanline < 240) {
|
if (_scanline >= -1 && _scanline < 240) {
|
||||||
|
|
||||||
|
if(_scanline == 0 && _column == 0) {
|
||||||
|
_column = 1;
|
||||||
|
}
|
||||||
|
|
||||||
if (_scanline == -1 && _column == 1) {
|
if (_scanline == -1 && _column == 1) {
|
||||||
_status.verticalBlank = 0;
|
_status.verticalBlank = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Preloading some data ahead of time
|
// Preloading some data ahead of time
|
||||||
if ((_column >= 2 && _column < 258) || (_column >= 321 && _column < 338)) {
|
if ((_column >= 2 && _column < 258) || (_column >= 321 && _column < 338)) {
|
||||||
// Every 8 ticks extract info about next tile
|
_bgPatternShifter.shift();
|
||||||
// Spread the work across those 8 ticks
|
_bgAttribShifter.shift();
|
||||||
switch ((_column - 1) % 8) {
|
_nextBgTile = prepareNextBgTile(_column);
|
||||||
case 0:
|
|
||||||
_nextBgTile.id = internalRead(0x2000 + _vRamAddress.value & 0x0FFF);
|
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
//_nextBgTile.attribute
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(_column == 256) {
|
||||||
|
incrementScrollY();
|
||||||
|
}
|
||||||
|
|
||||||
|
if(_column == 257) {
|
||||||
|
_bgPatternShifter.load(_nextBgTile.lsb, _nextBgTile.msb);
|
||||||
|
_bgAttribShifter.load((_nextBgTile.attribute & 0b01) ? 0xFF : 0x00,
|
||||||
|
(_nextBgTile.attribute & 0b10) ? 0xFF : 0x00);
|
||||||
|
updateScrollX();
|
||||||
|
}
|
||||||
|
|
||||||
|
if(_column == 338 || _column == 340) {
|
||||||
|
_nextBgTile.id = internalRead(0x2000 | (_vRamAddress.value & 0x0FFF));
|
||||||
|
}
|
||||||
|
|
||||||
|
if(_scanline == -1 && _column >= 280 && _column < 305) {
|
||||||
|
updateScrollY();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -117,6 +134,8 @@ namespace nes {
|
|||||||
// setPixel(_scanline, _column, pixel);
|
// setPixel(_scanline, _column, pixel);
|
||||||
|
|
||||||
if(_mask.renderBackground) {
|
if(_mask.renderBackground) {
|
||||||
|
colorIndex = _bgPatternShifter.getValue(_fineX);
|
||||||
|
palette = _bgAttribShifter.getValue(_fineX);
|
||||||
Pixel pixel = getColor(palette, colorIndex);
|
Pixel pixel = getColor(palette, colorIndex);
|
||||||
setPixel(_scanline, _column, pixel);
|
setPixel(_scanline, _column, pixel);
|
||||||
}
|
}
|
||||||
@ -211,8 +230,8 @@ namespace nes {
|
|||||||
return _cartridge->readChr(address);
|
return _cartridge->readChr(address);
|
||||||
}
|
}
|
||||||
else if(address >= 0x2000 && address < 0x3F00) {
|
else if(address >= 0x2000 && address < 0x3F00) {
|
||||||
address &= 0x03FF;
|
address &= 0x0FFF;
|
||||||
return _nameTable[address];
|
return _nameTable[address & 0x03FF];
|
||||||
}
|
}
|
||||||
else if(address >= 0x3F00 && address < 0x4000) {
|
else if(address >= 0x3F00 && address < 0x4000) {
|
||||||
address &= 0x1F;
|
address &= 0x1F;
|
||||||
@ -233,9 +252,8 @@ namespace nes {
|
|||||||
// Can't write to CHR ROM
|
// Can't write to CHR ROM
|
||||||
}
|
}
|
||||||
else if(address >= 0x2000 && address < 0x3F00) {
|
else if(address >= 0x2000 && address < 0x3F00) {
|
||||||
address &= 0x03FF;
|
address &= 0x0FFF;
|
||||||
//std::cout << std::hex << "Writing nametable, address: " << (int)address << ", value: " << (int)value << std::endl;
|
_nameTable[address & 0x03FF] = value;
|
||||||
_nameTable[address] = value;
|
|
||||||
}
|
}
|
||||||
else if(address >= 0x3F00 && address < 0x4000) {
|
else if(address >= 0x3F00 && address < 0x4000) {
|
||||||
address &= 0x1F;
|
address &= 0x1F;
|
||||||
@ -251,4 +269,96 @@ namespace nes {
|
|||||||
uint16_t address = 0x3F00 + palette*4 + pixel;
|
uint16_t address = 0x3F00 + palette*4 + pixel;
|
||||||
return _palette[internalRead(address) & 0x3F];
|
return _palette[internalRead(address) & 0x3F];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Ppu::TileInfo Ppu::prepareNextBgTile(uint16_t column) {
|
||||||
|
TileInfo nextBgTile{};
|
||||||
|
|
||||||
|
// Every 8 ticks extract info about next tile
|
||||||
|
// Spread the work across those 8 ticks
|
||||||
|
switch ((column - 1) % 8) {
|
||||||
|
case 0:
|
||||||
|
_bgPatternShifter.load(_nextBgTile.lsb, _nextBgTile.msb);
|
||||||
|
_bgAttribShifter.load((_nextBgTile.attribute & 0b01) ? 0xFF : 0x00,
|
||||||
|
(_nextBgTile.attribute & 0b10) ? 0xFF : 0x00);
|
||||||
|
nextBgTile.id = internalRead(0x2000 + _vRamAddress.value & 0x0FFF);
|
||||||
|
break;
|
||||||
|
case 2: {
|
||||||
|
uint16_t offset = (_vRamAddress.nameTableX << 10)
|
||||||
|
| (_vRamAddress.nameTableY << 11)
|
||||||
|
| (_vRamAddress.coarseX >> 2)
|
||||||
|
| ((_vRamAddress.coarseY >> 2) << 3);
|
||||||
|
nextBgTile.attribute = internalRead(0x23C0 + offset);
|
||||||
|
if (_vRamAddress.coarseY & 0x02) nextBgTile.attribute >>= 4;
|
||||||
|
if (_vRamAddress.coarseX & 0x02) nextBgTile.attribute >>= 2;
|
||||||
|
nextBgTile.attribute &= 0x03;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 4: {
|
||||||
|
uint16_t address = (_control.patternBackground << 12)
|
||||||
|
| ((uint16_t)nextBgTile.id << 4)
|
||||||
|
| _vRamAddress.fineY;
|
||||||
|
nextBgTile.lsb = internalRead(address);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 6: {
|
||||||
|
uint16_t address = (_control.patternBackground << 12)
|
||||||
|
| ((uint16_t)nextBgTile.id << 4)
|
||||||
|
| (_vRamAddress.fineY + 8);
|
||||||
|
nextBgTile.lsb = internalRead(address);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 7:
|
||||||
|
incrementScrollX();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return nextBgTile;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Ppu::incrementScrollX() {
|
||||||
|
if(!_mask.renderBackground)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if(_vRamAddress.coarseX == 31) {
|
||||||
|
_vRamAddress.coarseX = 0;
|
||||||
|
_vRamAddress.nameTableX = ~_vRamAddress.nameTableX;
|
||||||
|
} else {
|
||||||
|
_vRamAddress.coarseX++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Ppu::incrementScrollY() {
|
||||||
|
if(!_mask.renderBackground)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if(_vRamAddress.fineY < 7) {
|
||||||
|
_vRamAddress.fineY++;
|
||||||
|
} else {
|
||||||
|
_vRamAddress.fineY = 0;
|
||||||
|
|
||||||
|
if(_vRamAddress.coarseY == 29) {
|
||||||
|
_vRamAddress.coarseY = 0;
|
||||||
|
_vRamAddress.nameTableY = ~_vRamAddress.nameTableY;
|
||||||
|
} else if(_vRamAddress.coarseY == 31) {
|
||||||
|
_vRamAddress.coarseY = 0;
|
||||||
|
} else {
|
||||||
|
_vRamAddress.coarseY++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Ppu::updateScrollX() {
|
||||||
|
if(_mask.renderBackground) {
|
||||||
|
_vRamAddress.nameTableX = _tRamAddress.nameTableX;
|
||||||
|
_vRamAddress.coarseX = _tRamAddress.coarseX;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Ppu::updateScrollY() {
|
||||||
|
if(_mask.renderBackground) {
|
||||||
|
_vRamAddress.nameTableY =_tRamAddress.nameTableY;
|
||||||
|
_vRamAddress.coarseY = _tRamAddress.coarseY;
|
||||||
|
_vRamAddress.fineY = _tRamAddress.fineY;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@ -6,6 +6,7 @@
|
|||||||
#define NES_PPU_H
|
#define NES_PPU_H
|
||||||
|
|
||||||
#include "Cartridge.h"
|
#include "Cartridge.h"
|
||||||
|
#include "Shifter.h"
|
||||||
|
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
@ -111,6 +112,11 @@ namespace nes {
|
|||||||
uint8_t internalRead(uint16_t address);
|
uint8_t internalRead(uint16_t address);
|
||||||
void internalWrite(uint16_t address, uint8_t value);
|
void internalWrite(uint16_t address, uint8_t value);
|
||||||
Pixel getColor(uint8_t palette, uint8_t pixel);
|
Pixel getColor(uint8_t palette, uint8_t pixel);
|
||||||
|
TileInfo prepareNextBgTile(uint16_t column);
|
||||||
|
void incrementScrollX();
|
||||||
|
void incrementScrollY();
|
||||||
|
void updateScrollX();
|
||||||
|
void updateScrollY();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
int16_t _column;
|
int16_t _column;
|
||||||
@ -125,6 +131,8 @@ namespace nes {
|
|||||||
uint8_t _dataTemp;
|
uint8_t _dataTemp;
|
||||||
uint8_t _fineX;
|
uint8_t _fineX;
|
||||||
TileInfo _nextBgTile;
|
TileInfo _nextBgTile;
|
||||||
|
Shifter _bgPatternShifter;
|
||||||
|
Shifter _bgAttribShifter;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::unique_ptr<uint8_t[]> _nameTable;
|
std::unique_ptr<uint8_t[]> _nameTable;
|
||||||
|
|||||||
28
src/Shifter.cpp
Normal file
28
src/Shifter.cpp
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
//
|
||||||
|
// Created by Selim Mustafaev on 09.09.2023.
|
||||||
|
//
|
||||||
|
|
||||||
|
#include "Shifter.h"
|
||||||
|
|
||||||
|
namespace nes {
|
||||||
|
|
||||||
|
Shifter::Shifter(): _lo{}, _hi{} {
|
||||||
|
}
|
||||||
|
|
||||||
|
void Shifter::load(uint8_t lo, uint8_t hi) {
|
||||||
|
_lo = (_lo & 0xFF00) | lo;
|
||||||
|
_hi = (_hi & 0xFF00) | hi;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Shifter::shift() {
|
||||||
|
_lo <<= 1;
|
||||||
|
_hi <<= 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t Shifter::getValue(uint8_t offset) {
|
||||||
|
uint16_t mask = 0x8000 >> offset;
|
||||||
|
bool loBit = _lo & mask;
|
||||||
|
bool hiBit = _hi & mask;
|
||||||
|
return (hiBit << 1) | loBit;
|
||||||
|
}
|
||||||
|
}
|
||||||
26
src/Shifter.h
Normal file
26
src/Shifter.h
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
//
|
||||||
|
// Created by Selim Mustafaev on 09.09.2023.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef NES_SHIFTER_H
|
||||||
|
#define NES_SHIFTER_H
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
|
namespace nes {
|
||||||
|
|
||||||
|
class Shifter {
|
||||||
|
public:
|
||||||
|
Shifter();
|
||||||
|
void load(uint8_t lo, uint8_t hi);
|
||||||
|
void shift();
|
||||||
|
uint16_t getValue(uint8_t offset);
|
||||||
|
|
||||||
|
private:
|
||||||
|
uint16_t _lo;
|
||||||
|
uint16_t _hi;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif //NES_SHIFTER_H
|
||||||
Loading…
Reference in New Issue
Block a user