#include "DisplaySDL.hpp" #include "Peripherals.hpp" #include DisplaySDL::DisplaySDL(int w, int h, uint32_t fgColor, uint32_t bgColor): mpFramebuffer{std::make_unique()} { // Create SDL Window mpWindow = SDL_CreateWindow( "ChocoChip-8", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, w, h, 0 ); if(mpWindow == NULL) { throw std::runtime_error(SDL_GetError()); } // Convert our foreground/background colors to the format expected by SDL SDL_PixelFormat *fmt = SDL_AllocFormat(SDL_GetWindowPixelFormat(mpWindow)); mFgColor = SDL_MapRGB( fmt, (fgColor & 0x00FF0000) >> 16, (fgColor & 0x0000FF00) >> 8, (fgColor & 0x000000FF) ); mBgColor = SDL_MapRGB( fmt, (bgColor & 0x00FF0000) >> 16, (bgColor & 0x0000FF00) >> 8, (bgColor & 0x000000FF) ); SDL_FreeFormat(fmt); }; DisplaySDL::~DisplaySDL() { SDL_DestroyWindow(mpWindow); } void DisplaySDL::clear() { for(auto &scanline : *mpFramebuffer) { scanline.reset(); } SDL_FillRect(SDL_GetWindowSurface(mpWindow), nullptr, mBgColor); } int DisplaySDL::blit(const chocochip8::Scanline &spriteScanline, int y) { using chocochip8::Scanline; Scanline &targetScanline = mpFramebuffer->at(y); Scanline bitsToSet = spriteScanline & ~targetScanline; Scanline bitsToReset = spriteScanline & targetScanline; targetScanline ^= spriteScanline; SDL_Surface *pSurface = SDL_GetWindowSurface(mpWindow); SDL_Rect rect; // Map framebuffer pixel to SDL surface rectangle auto mapChipxelToPixel = [&rect, pSurface](int x, int y) { // Note that the MSB of an scanline's bitset is the leftmost pixel. x = (chocochip8::gcWidth - 1) - x; int x1 = ( x * pSurface->w) / chocochip8::gcWidth; int x2 = ((x + 1) * pSurface->w) / chocochip8::gcWidth; int y1 = ( y * pSurface->h) / chocochip8::gcHeight; int y2 = ((y + 1) * pSurface->h) / chocochip8::gcHeight; rect.x = x1; rect.y = y1; rect.w = x2 - x1; rect.h = y2 - y1; }; for(int x = bitsToReset._Find_first(); x < bitsToReset.size(); x = bitsToReset._Find_next(x)) { mapChipxelToPixel(x, y); SDL_FillRect(pSurface, &rect, mBgColor); } for(int x = bitsToSet._Find_first(); x < bitsToSet.size(); x = bitsToSet._Find_next(x)) { mapChipxelToPixel(x, y); SDL_FillRect(pSurface, &rect, mFgColor); } return bitsToReset.any(); } void DisplaySDL::updateWindow() const { SDL_UpdateWindowSurface(mpWindow); }