Adding background shifters
This commit is contained in:
parent
d07f61b081
commit
40c7ff5882
@ -25,4 +25,5 @@ add_executable(nes
|
||||
src/Shifter.h)
|
||||
|
||||
find_package(SDL2 CONFIG REQUIRED)
|
||||
target_link_libraries(nes PRIVATE SDL2::SDL2)
|
||||
find_package(fmt REQUIRED)
|
||||
target_link_libraries(nes PRIVATE SDL2::SDL2 fmt::fmt)
|
||||
4
main.cpp
4
main.cpp
@ -11,10 +11,12 @@ int main() {
|
||||
|
||||
nes::Nes device;
|
||||
nes::SdlWindow window(nes::Ppu::SCREEN_WIDTH, nes::Ppu::SCREEN_HEIGHT);
|
||||
window.setSize(nes::Ppu::SCREEN_WIDTH * 4, nes::Ppu::SCREEN_HEIGHT * 4);
|
||||
|
||||
device.setNewFrameCallback(std::bind(&nes::SdlWindow::drawFrame, &window, _1));
|
||||
//device.insertCartridge("/home/selim/Downloads/nestest.nes");
|
||||
device.insertCartridge("/Users/selim/Documents/nestest.nes");
|
||||
//device.insertCartridge("/Users/selim/Documents/nestest.nes");
|
||||
device.insertCartridge("C:\\Users\\selim\\Documents\\nestest.nes");
|
||||
|
||||
SDL_Event e;
|
||||
uint64_t cycles = 0;
|
||||
|
||||
@ -25,6 +25,7 @@ namespace nes {
|
||||
|
||||
void Nes::reset(std::optional<uint16_t> address) {
|
||||
_cpu->reset();
|
||||
_ppu->reset();
|
||||
if(address) {
|
||||
_cpu->setStartAddress(address.value());
|
||||
}
|
||||
|
||||
73
src/Ppu.cpp
73
src/Ppu.cpp
@ -4,8 +4,6 @@
|
||||
|
||||
#include "Ppu.h"
|
||||
|
||||
#include <iostream>
|
||||
|
||||
namespace nes {
|
||||
|
||||
Ppu::Ppu(): _column{}, _scanline{}, _status{}, _control{}, _mask{} {
|
||||
@ -101,7 +99,7 @@ namespace nes {
|
||||
if ((_column >= 2 && _column < 258) || (_column >= 321 && _column < 338)) {
|
||||
_bgPatternShifter.shift();
|
||||
_bgAttribShifter.shift();
|
||||
_nextBgTile = prepareNextBgTile(_column);
|
||||
prepareNextBgTile(_column);
|
||||
}
|
||||
|
||||
if(_column == 256) {
|
||||
@ -128,15 +126,20 @@ namespace nes {
|
||||
uint8_t palette = 0;
|
||||
|
||||
if(_column < SCREEN_WIDTH && _scanline < SCREEN_HEIGHT && _scanline >= 0) {
|
||||
// Pixel black = {0, 0, 0, 100};
|
||||
// Pixel white = {255, 255, 255, 100};
|
||||
// Pixel pixel = std::rand() % 2 == 0 ? black : white;
|
||||
// setPixel(_scanline, _column, pixel);
|
||||
|
||||
if(_mask.renderBackground) {
|
||||
colorIndex = _bgPatternShifter.getValue(_fineX);
|
||||
palette = _bgAttribShifter.getValue(_fineX);
|
||||
Pixel pixel = getColor(palette, colorIndex);
|
||||
|
||||
// For debugging
|
||||
if (colorIndex != 0) {
|
||||
pixel = Pixel(0xFF, 0xFF, 0xFF);
|
||||
}
|
||||
else {
|
||||
pixel = Pixel();
|
||||
}
|
||||
|
||||
setPixel(_scanline, _column, pixel);
|
||||
}
|
||||
}
|
||||
@ -223,6 +226,22 @@ namespace nes {
|
||||
_cartridge = std::move(cartridge);
|
||||
}
|
||||
|
||||
void Ppu::reset() {
|
||||
_column = 0;
|
||||
_scanline = 0;
|
||||
_status.value = 0;
|
||||
_control.value = 0;
|
||||
_mask.value = 0;
|
||||
_vRamAddress.value = 0;
|
||||
_tRamAddress.value = 0;
|
||||
_addressWriteInProgress = false;
|
||||
_dataTemp = 0;
|
||||
_fineX = 0;
|
||||
_nextBgTile = { 0, 0, 0, 0 };
|
||||
_bgPatternShifter = {};
|
||||
_bgAttribShifter = {};
|
||||
}
|
||||
|
||||
uint8_t Ppu::internalRead(uint16_t address) {
|
||||
address &= 0x3FFF;
|
||||
|
||||
@ -254,6 +273,9 @@ namespace nes {
|
||||
else if(address >= 0x2000 && address < 0x3F00) {
|
||||
address &= 0x0FFF;
|
||||
_nameTable[address & 0x03FF] = value;
|
||||
if (value == 32) {
|
||||
int x = 0;
|
||||
}
|
||||
}
|
||||
else if(address >= 0x3F00 && address < 0x4000) {
|
||||
address &= 0x1F;
|
||||
@ -270,8 +292,7 @@ namespace nes {
|
||||
return _palette[internalRead(address) & 0x3F];
|
||||
}
|
||||
|
||||
Ppu::TileInfo Ppu::prepareNextBgTile(uint16_t column) {
|
||||
TileInfo nextBgTile{};
|
||||
void Ppu::prepareNextBgTile(uint16_t column) {
|
||||
|
||||
// Every 8 ticks extract info about next tile
|
||||
// Spread the work across those 8 ticks
|
||||
@ -280,43 +301,41 @@ namespace nes {
|
||||
_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);
|
||||
_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;
|
||||
_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)
|
||||
| ((uint16_t)_nextBgTile.id << 4)
|
||||
| _vRamAddress.fineY;
|
||||
nextBgTile.lsb = internalRead(address);
|
||||
break;
|
||||
_nextBgTile.lsb = internalRead(address);
|
||||
}
|
||||
break;
|
||||
case 6: {
|
||||
uint16_t address = (_control.patternBackground << 12)
|
||||
| ((uint16_t)nextBgTile.id << 4)
|
||||
| ((uint16_t)_nextBgTile.id << 4)
|
||||
| (_vRamAddress.fineY + 8);
|
||||
nextBgTile.lsb = internalRead(address);
|
||||
break;
|
||||
_nextBgTile.lsb = internalRead(address);
|
||||
}
|
||||
break;
|
||||
case 7:
|
||||
incrementScrollX();
|
||||
break;
|
||||
}
|
||||
|
||||
return nextBgTile;
|
||||
}
|
||||
|
||||
void Ppu::incrementScrollX() {
|
||||
if(!_mask.renderBackground)
|
||||
if(!_mask.renderBackground && !_mask.renderSprites)
|
||||
return;
|
||||
|
||||
if(_vRamAddress.coarseX == 31) {
|
||||
@ -328,7 +347,7 @@ namespace nes {
|
||||
}
|
||||
|
||||
void Ppu::incrementScrollY() {
|
||||
if(!_mask.renderBackground)
|
||||
if(!_mask.renderBackground && !_mask.renderSprites)
|
||||
return;
|
||||
|
||||
if(_vRamAddress.fineY < 7) {
|
||||
@ -348,14 +367,14 @@ namespace nes {
|
||||
}
|
||||
|
||||
void Ppu::updateScrollX() {
|
||||
if(_mask.renderBackground) {
|
||||
if(_mask.renderBackground && !_mask.renderSprites) {
|
||||
_vRamAddress.nameTableX = _tRamAddress.nameTableX;
|
||||
_vRamAddress.coarseX = _tRamAddress.coarseX;
|
||||
}
|
||||
}
|
||||
|
||||
void Ppu::updateScrollY() {
|
||||
if(_mask.renderBackground) {
|
||||
if(_mask.renderBackground && !_mask.renderSprites) {
|
||||
_vRamAddress.nameTableY =_tRamAddress.nameTableY;
|
||||
_vRamAddress.coarseY = _tRamAddress.coarseY;
|
||||
_vRamAddress.fineY = _tRamAddress.fineY;
|
||||
|
||||
@ -20,7 +20,7 @@ namespace nes {
|
||||
uint8_t B = 0;
|
||||
uint8_t A = 0xFF;
|
||||
|
||||
Pixel(): R{}, G{}, B{}, A{} {}
|
||||
Pixel(): R{}, G{}, B{}, A{0xFF} {}
|
||||
Pixel(uint8_t R, uint8_t G, uint8_t B): R{R}, G{G}, B{B}, A{0xFF} {}
|
||||
};
|
||||
|
||||
@ -104,6 +104,7 @@ namespace nes {
|
||||
uint8_t read(uint16_t address);
|
||||
void setPixel(uint16_t row, uint16_t column, Pixel pixel);
|
||||
void connect(std::shared_ptr<Cartridge> cartridge);
|
||||
void reset();
|
||||
|
||||
public:
|
||||
std::function<void(const Pixel*)> onNewFrame;
|
||||
@ -112,7 +113,7 @@ namespace nes {
|
||||
uint8_t internalRead(uint16_t address);
|
||||
void internalWrite(uint16_t address, uint8_t value);
|
||||
Pixel getColor(uint8_t palette, uint8_t pixel);
|
||||
TileInfo prepareNextBgTile(uint16_t column);
|
||||
void prepareNextBgTile(uint16_t column);
|
||||
void incrementScrollX();
|
||||
void incrementScrollY();
|
||||
void updateScrollX();
|
||||
|
||||
@ -14,10 +14,12 @@ namespace nes {
|
||||
_wnd.reset(SDL_CreateWindow("NES", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, width, height, flags));
|
||||
if(!_wnd) throw std::runtime_error("Error creating SDL window");
|
||||
|
||||
SDL_SetWindowResizable(_wnd.get(), SDL_TRUE);
|
||||
|
||||
_renderer.reset(SDL_CreateRenderer(_wnd.get(), -1, 0));
|
||||
if(!_renderer) throw std::runtime_error("Error creating SDL renderer");
|
||||
|
||||
_texture.reset(SDL_CreateTexture(_renderer.get(), SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_STREAMING, width, height));
|
||||
_texture.reset(SDL_CreateTexture(_renderer.get(), SDL_PIXELFORMAT_ABGR8888, SDL_TEXTUREACCESS_STREAMING, width, height));
|
||||
if(!_texture) throw std::runtime_error("Error creating SDL texture");
|
||||
}
|
||||
|
||||
@ -28,4 +30,8 @@ namespace nes {
|
||||
SDL_RenderCopy(_renderer.get(), _texture.get(), nullptr, nullptr);
|
||||
SDL_RenderPresent(_renderer.get());
|
||||
}
|
||||
|
||||
void SdlWindow::setSize(int width, int height) {
|
||||
SDL_SetWindowSize(_wnd.get(), width, height);
|
||||
}
|
||||
}
|
||||
@ -28,6 +28,7 @@ namespace nes {
|
||||
public:
|
||||
SdlWindow(uint16_t width, uint16_t height);
|
||||
void drawFrame(const Pixel* buffer);
|
||||
void setSize(int width, int height);
|
||||
|
||||
private:
|
||||
uint16_t _width;
|
||||
|
||||
14
vcpkg.json
14
vcpkg.json
@ -2,8 +2,14 @@
|
||||
"name" : "nes",
|
||||
"version-string" : "1.0.0",
|
||||
"builtin-baseline" : "c95000e1b5bb62884de08d5e952993c8bced9db6",
|
||||
"dependencies" : [ {
|
||||
"name" : "sdl2",
|
||||
"version>=" : "2.26.5"
|
||||
} ]
|
||||
"dependencies": [
|
||||
{
|
||||
"name": "sdl2",
|
||||
"version>=": "2.26.5"
|
||||
},
|
||||
{
|
||||
"name": "fmt",
|
||||
"version>=": "10.0.0"
|
||||
}
|
||||
]
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user