From 40c7ff5882f81f06a9468fa3d1b8348b79ee00a5 Mon Sep 17 00:00:00 2001 From: Selim Mustafaev Date: Sun, 10 Sep 2023 22:17:15 +0300 Subject: [PATCH] Adding background shifters --- CMakeLists.txt | 3 ++- main.cpp | 4 ++- src/Nes.cpp | 1 + src/Ppu.cpp | 73 +++++++++++++++++++++++++++++++------------------- src/Ppu.h | 5 ++-- src/Window.cpp | 8 +++++- src/Window.h | 1 + vcpkg.json | 14 +++++++--- 8 files changed, 73 insertions(+), 36 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index e5053ab..a5bdc14 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -25,4 +25,5 @@ add_executable(nes src/Shifter.h) find_package(SDL2 CONFIG REQUIRED) -target_link_libraries(nes PRIVATE SDL2::SDL2) \ No newline at end of file +find_package(fmt REQUIRED) +target_link_libraries(nes PRIVATE SDL2::SDL2 fmt::fmt) \ No newline at end of file diff --git a/main.cpp b/main.cpp index 1dd10a2..bb94afb 100644 --- a/main.cpp +++ b/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; diff --git a/src/Nes.cpp b/src/Nes.cpp index d2e367c..6cee319 100644 --- a/src/Nes.cpp +++ b/src/Nes.cpp @@ -25,6 +25,7 @@ namespace nes { void Nes::reset(std::optional address) { _cpu->reset(); + _ppu->reset(); if(address) { _cpu->setStartAddress(address.value()); } diff --git a/src/Ppu.cpp b/src/Ppu.cpp index db6ac79..6318a97 100644 --- a/src/Ppu.cpp +++ b/src/Ppu.cpp @@ -4,8 +4,6 @@ #include "Ppu.h" -#include - 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; diff --git a/src/Ppu.h b/src/Ppu.h index d294521..564b7de 100644 --- a/src/Ppu.h +++ b/src/Ppu.h @@ -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); + void reset(); public: std::function 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(); diff --git a/src/Window.cpp b/src/Window.cpp index b90953d..cb9e86a 100644 --- a/src/Window.cpp +++ b/src/Window.cpp @@ -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); + } } \ No newline at end of file diff --git a/src/Window.h b/src/Window.h index a3fbd68..790504c 100644 --- a/src/Window.h +++ b/src/Window.h @@ -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; diff --git a/vcpkg.json b/vcpkg.json index 6a8d7b5..9d47d8f 100644 --- a/vcpkg.json +++ b/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" + } + ] } \ No newline at end of file