Thomas
Thomas

Reputation: 1143

Rendering parts of the screen on each frame with SDL2

I am making a 2D game in C++ using SDL2 in which the world map is made up of 120x67 tiles. At any given time, there will only be about 20 or so sprites (each taking up exactly one tile) moving around on the map, and only a small portion of the tiles (mainly just water tiles) will be animated. So for a vast majority of the time, the majority of the tiles will remain static. Currently, I have a simple draw loop that iterates over all the tiles and redraws them:

/* Drawing loop, excluding frame rate limiting logic and updating gamestate */
while(true) {

    /* game state is updated (omitted) */

    /* clear the entire screen */
    SDL_RenderClear(renderer);

    /* loop through all the tiles and redraw them */
    for (int i = 0; i < rows; i++) {
        for(int j = 0; j < cols; j++) {

            /* call the tile's draw method, which calls SDL_renderCopy()
             * to draw the tile background and sprite (if there is one) */
            tiles[i][j].drawTile(renderer);
        }
    }

    /* output everything to the screen */
    SDL_RenderPresent(renderer);
}

However, since most of the tiles will remain static most of the time, there is no need to keep drawing them. It would be much more efficient to only redraw the small portions of the screen that are changing. So my new idea is, while updating the game state, add all the updated tiles to a list, and then simply redraw only the updated tiles on each frame, like so:

/* Drawing loop that only redraws updated tiles */
while(true) {

    /* game state is updated, updated tiles added to a list (omitted) */

    /* loop through only the updated tiles and redraw them */
    for (std::list<Tile>::iterator it=updatedTiles.begin(); it != updatedTiles.end(); ++it) {

        /* call the tile's draw method, which calls SDL_renderCopy()
         * to draw the tile background and sprite (if there is one) */
        it->drawTile(renderer);
    }

    /* output everything to the screen */
    SDL_RenderPresent(renderer);
}

Since I don't want to clear the screen before each frame, the call to SDL_RenderClear() is removed in the second case. However, from the SDL2 documentation for SDL_RenderPresent found here, it says:

You are strongly encouraged to call SDL_RenderClear() to initialize the backbuffer before starting each new frame's drawing.

With this, my two questions are:

  1. Do I really need to call SDL_RenderClear() on each frame if I intened to only update the modified tiles?
  2. If I have to stick with redrawing every tile on every frame, are modern graphics cards / the SDL library "smart" enough to, on the call to SDL_RenderPresent(), only redraw the parts of the screen that were changed, without me having to implement this?

Upvotes: 3

Views: 2928

Answers (1)

skypjack
skypjack

Reputation: 50568

The relevant part of the documentation is immediately before the one you mentioned (emphasis mine)

The backbuffer should be considered invalidated after each present; do not assume that previous contents will exist between frames.

It means that a call to SDL_RenderClear is mandatory more than suggested.

What you can do instead is to draw the background image (whatever it means, as an example the set of tiles where you don't have any PC or NPC around) on a targeted texture only once before to enter the scene (see SDL_SetRenderTarget and the other functions around for more details). Then, within the loop, you can clear the default renderer, copy that image at once as a background image and finally draw only the updated tiles over it, thus updating their (let me say) default or basic representation.
In fact, if you have updated N tiles, you end up drawing everything with N+1 calls to SDL_RenderCopy or whatever at each iteration.

To be honest, I would do that only if you are observing a significant drop of frames due to the fact that you are drawing too much at each iteration. My two cents.
Anyway it's a dirty and working solution that does what you want at least.

Upvotes: 2

Related Questions