diff --git a/.gitignore b/.gitignore index 3bdae91..fff52d5 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,6 @@ cmake-build-debug/ .idea/ .vs/ -out/ \ No newline at end of file +out/ +build/ +CMakeLists.txt.user diff --git a/examples/sdl/main.cpp b/examples/sdl/main.cpp index 1fd35d0..e152105 100644 --- a/examples/sdl/main.cpp +++ b/examples/sdl/main.cpp @@ -2,7 +2,6 @@ #include "Window.h" #include "SdlKeyboardController.h" -#include #include int main() { @@ -12,25 +11,34 @@ int main() { nes::System device; nes::SdlWindow window(nes::Ppu::SCREEN_WIDTH, nes::Ppu::SCREEN_HEIGHT); window.setSize(nes::Ppu::SCREEN_WIDTH*2, nes::Ppu::SCREEN_HEIGHT*2); - + bool working = true; SDL_Event e; - bool frameRendered = false; - device.setNewFrameCallback([&window, &e, &frameRendered](auto buffer){ - window.drawFrame(buffer); - while(SDL_PollEvent(&e)); - frameRendered = true; - }); + device.connect(std::make_shared()); //device.insertCartridge("/home/selim/Downloads/dk.nes"); - device.insertCartridge("/Users/selim/Documents/nes/ppu_tests/sprite_ram.nes"); + device.insertCartridge("/Users/selim/Documents/nes/ppu_tests/vram_access.nes"); //device.insertCartridge("/Users/selim/Documents/nes/ff.nes"); //device.insertCartridge("C:\\Users\\selim\\Documents\\nestest.nes"); auto frameStart = std::chrono::steady_clock::now(); - while (true) { - device.tick(); + while (working) { - if(frameRendered) { + if(auto frameBuffer = device.tick()) { + + // Draw frame + window.drawFrame(frameBuffer); + + // Poll all accumulated events + while(SDL_PollEvent(&e)) { + switch(e.type) { + case SDL_EVENT_WINDOW_CLOSE_REQUESTED: + case SDL_EVENT_QUIT: + working = false; + break; + } + } + + // Wait some time for slowing down to 60 fps auto renderingTime = std::chrono::steady_clock::now(); auto elapsedTime = std::chrono::duration_cast(renderingTime - frameStart).count(); int64_t waitTime = 1000000000/60 - elapsedTime; @@ -38,7 +46,6 @@ int main() { std::this_thread::sleep_for(std::chrono::nanoseconds(waitTime)); } frameStart = std::chrono::steady_clock::now(); - frameRendered = false; } } diff --git a/src/Ppu.cpp b/src/Ppu.cpp index f910cb6..7c307b2 100644 --- a/src/Ppu.cpp +++ b/src/Ppu.cpp @@ -34,7 +34,7 @@ namespace nes { }; } - bool Ppu::tick() { + std::tuple Ppu::tick() { _needEmitNmi = false; @@ -148,17 +148,22 @@ namespace nes { } _column++; + bool frameReady = false; + if(_column >= 341) { _column = 0; _scanline++; if(_scanline >= 261) { _scanline = -1; - onNewFrame(_frameBuffer.get()); + frameReady = true; } } - return _needEmitNmi; + return { + _needEmitNmi, + frameReady ? _frameBuffer.get() : nullptr + }; } uint8_t Ppu::read(uint16_t address) { diff --git a/src/Ppu.h b/src/Ppu.h index fe42f27..bef4b9a 100644 --- a/src/Ppu.h +++ b/src/Ppu.h @@ -13,6 +13,7 @@ #include #include #include +#include namespace nes { @@ -101,7 +102,7 @@ namespace nes { public: Ppu(); - bool tick(); + std::tuple tick(); void write(uint16_t address, uint8_t value); uint8_t read(uint16_t address); void setPixel(uint16_t row, uint16_t column, Pixel pixel); @@ -115,9 +116,6 @@ namespace nes { void dmaTick(uint64_t cycles) const; void startDma(uint8_t page) const; - public: - std::function onNewFrame; - private: Pixel getColor(uint8_t palette, uint8_t pixel); void prepareNextBgTile(uint16_t column); diff --git a/src/System.cpp b/src/System.cpp index d99f53f..fa5fec7 100644 --- a/src/System.cpp +++ b/src/System.cpp @@ -44,12 +44,8 @@ namespace nes { } } - void System::setNewFrameCallback(std::function onNewFrame) { - _ppu->onNewFrame = std::move(onNewFrame); - } - - void System::tick() { - bool needInterrupt = _ppu->tick(); + const Pixel* System::tick() { + auto [needInterrupt, frameBuffer] = _ppu->tick(); if(_cycles % 3 == 0) { if(_ppu->dmaActive()) { @@ -64,6 +60,8 @@ namespace nes { } _cycles++; + + return frameBuffer; } // For debug diff --git a/src/System.h b/src/System.h index cfcb327..fc8acab 100644 --- a/src/System.h +++ b/src/System.h @@ -27,8 +27,7 @@ namespace nes { void insertCartridge(const fs::path& path, std::optional address = std::nullopt); void connect(std::shared_ptr controller); void reset(std::optional address = std::nullopt); - void setNewFrameCallback(std::function onNewFrame); - void tick(); + const Pixel* tick(); [[nodiscard]] uint32_t zpHash() const;