#include "DisplaySDL.hpp" #include DisplaySDL::DisplaySDL(int w, int h, uint32_t fgColor, uint32_t bgColor) { // 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::updateWindow() const { if(miTopDirtyScanline > miBottomDirtyScanline) { // No changes since the last update return; } SDL_Surface *pSurface = SDL_GetWindowSurface(mpWindow); SDL_LockSurface(pSurface); int fx, fy; // ChocoChip8 Framebuffer coordinates int sx, sy; // SDL Surface coordinates int lx, ly; // Last-used ChocoChip8 Framebuffer coordinates Uint32 lc; // Last-used SDL color // Fill the entire SDL surface, one pixel at a time lx = -1; ly = -1; for(sy = 0; sy < pSurface->h; sy++) { // Map SDL surface coordinates to Chocochip8 Framebuffer coordinates fy = sy * (double(chocochip8::gcHeight) / pSurface->h); if(fy < miTopDirtyScanline || miBottomDirtyScanline < fy) { // Skip scanlines that haven't changed since the last update continue; } for(sx = 0; sx < pSurface->w; sx++) { fx = sx * (double(chocochip8::gcWidth) / pSurface->w); // Reuse color if this screen pixel maps to the same ChocoChip8 pixel as the last if(fx != lx || fy != ly) { lx = fx; ly = ly; // Read Chocochip8 Framebuffer and choose appropriate color, // note that the MSB of an scanline's bitset is the leftmost pixel. lc = (mpFramebuffer->at(fy)[(chocochip8::gcWidth - 1) - fx] ? mFgColor : mBgColor); } // Convert (x, y) indexes into SDL Surface pixel array index Uint32 *pPixel = static_cast(static_cast( static_cast(pSurface->pixels) + sy * pSurface->pitch + sx * pSurface->format->BytesPerPixel )); *pPixel = lc; } } miTopDirtyScanline = chocochip8::gcHeight - 1; miBottomDirtyScanline = 0; SDL_UnlockSurface(pSurface); SDL_UpdateWindowSurface(mpWindow); }