Saving screenshots is a simple and common feature in many games. It allows us to capture the image of the game being rendered on the screen at any given time.
While this might sound easy, let us remember that the image rendered to the screen might have a lot of different overlaid surfaces, meaning that it would be a pain to recompose that image on the side of the CPU in the same way that we’re composing the image to the texture that eventually ends up in video memory.
Fortunately, this Stack Overflow answer provides a simple solution. SDL2 provides the SDL_RenderReadPixels() function, which can be used to read pixel data back from video memory. This is generally discouraged, because it is very costly to do such a thing, but taking screenshots is a one-off operation where it makes perfect sense.
The following code shows how screenshot capture was implemented in Ultima 1 Revenge. It is only slightly different from the code in the aforementioned Stack Overflow answer:
void SosariaInputController::SaveScreenshot() { const Uint32 format = SDL_PIXELFORMAT_ARGB8888; const int width = 640; const int height = 400; auto renderer = sdl2Core->GetRenderer(); SDL_Surface *surface = SDL_CreateRGBSurfaceWithFormat(0, width, height, 32, format); SDL_RenderReadPixels(renderer, NULL, format, surface->pixels, surface->pitch); SDL_SaveBMP(surface, "screenshot.bmp"); SDL_FreeSurface(surface); }
While I am not showing where the sdl2Core
object is coming from, just assume that it stores an instance of SDL_Renderer. With that available, all that is needed is to create a surface using one of the functions that SDL2 provides, call SDL_RenderReadPixels() to transfer the pixels from video memory to the surface, and then actually do something with the surface (in this case, we are saving it to a bitmap file). If you wanted to read back only a portion of the screen, you would pass in an SDL_Rect
instead of NULL
as the second parameter to SDL_RenderReadPixels()
.
This simple code is used to save screenshots in Ultima 1 Revenge, such as the one shown earlier.