0
\$\begingroup\$

In order to run a game without using the CPU/GPU too much, I want to only update the section of the window that has changed.

Does this goal even make sense? How does the texture objects/renderer work when updating the screen? My idea is that the renderer builds a matrix of ints (pixel colours) and when SDL_RenderPresent is called, this edits a matrix stored on the memory that controls the colours for each pixel on the screen.

If what I've said so far makes sense, then is my implementation below correct (not updating more of the screen than needed)? I've tried to keep my code very, very simple so that it's easy to read.

The programme jumps the character (picture of a prince) from the top-left of the window to the bottom-left, and visa-versa, whenever the user inputs anything. This is just to keep the code simple for the example.

#include <iostream> #include <SDL2/SDL.h> #include <SDL2/SDL_image.h> using namespace std; int main () { // Screen dimension constants const int WINDOW_WIDTH = 639; const int WINDOW_HEIGHT = 1015; const int PRINCE_WIDTH = 74; const int PRINCE_HEIGHT = 114; SDL_Init ( SDL_INIT_EVERYTHING ); SDL_Window * window = SDL_CreateWindow ( "example", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, WINDOW_WIDTH, WINDOW_HEIGHT, SDL_WINDOW_SHOWN ); SDL_Renderer * renderer = SDL_CreateRenderer ( window, -1, SDL_RENDERER_ACCELERATED ); SDL_Texture * background = IMG_LoadTexture ( renderer, "./images/background.bmp" ); SDL_Rect rect_background = { 0, 0, WINDOW_WIDTH, WINDOW_HEIGHT }; SDL_RenderCopy ( renderer, background, & rect_background, & rect_background ); const SDL_Rect rect_place_one = { 400, 600, PRINCE_WIDTH, PRINCE_HEIGHT }; const SDL_Rect rect_place_two = { 40, 60, PRINCE_WIDTH, PRINCE_HEIGHT }; SDL_Texture * prince = IMG_LoadTexture ( renderer, "./images/prince.bmp" ); SDL_RenderCopy ( renderer, prince, NULL, & rect_place_one ); SDL_RenderPresent ( renderer ); SDL_Event input; for ( uint8_t count = 0; SDL_WaitEvent( & input ); ++count ) { // User requests quit if ( input.type == SDL_QUIT ) break; if ( input.type != SDL_KEYDOWN ) continue; if ( ( count % 2 ) ) { SDL_RenderCopy ( renderer, prince, NULL, & rect_place_one ); SDL_RenderCopy ( renderer, background, & rect_place_two, & rect_place_two ); } else { SDL_RenderCopy ( renderer, prince, NULL, & rect_place_two ); SDL_RenderCopy ( renderer, background, & rect_place_one, & rect_place_one ); } SDL_RenderPresent ( renderer ); } SDL_DestroyTexture ( prince ); SDL_DestroyTexture ( background ); SDL_RenderClear (renderer); SDL_DestroyWindow ( window ); SDL_Quit (); return 0; } 
\$\endgroup\$

1 Answer 1

3
\$\begingroup\$

Your idea is essentially software rendering, where you manually update pixels in a grid and then update those pixels to the screen. Only updating the necessary pixels in that case makes a lot of sense, since copying pure image data like that can be really slow.

I would heavily recommend against this approach. GPUs are really fast nowadays, and SDL2's renderer can take full advantage of the hardware acceleration that is provided by the graphics processor. Redrawing the screen each frame will be no issue at all, and your rendering pipeline will stay a lot simpler if you don't have to track down the screen areas that have changed, removing the possibility of odd ghosting bugs appearing.

SDL2's renderer is essentially a wrapper around OpenGL, DirectX or Metal. There is also a software renderer implementation, when none of the hardware accelerated graphics APIs aren't available for use, but for common platforms, there will always be a valid accelerated renderer that SDL can instantiate for you.

Your implementation looks relatively okay, however a more common approach is to place the event loop inside a separate gameloop. Currently you stop updating if there are no events to process.

while (runGame) { SDL_Event e; while (SDL_PollEvent(&e)) { // Process events. } updateGame(); SDL_RenderClear(renderer); renderGame(); SDL_RenderPresent(renderer); } 

Here is a very basic outline of a common game loop. There are bits missing, like timing, but getting into that stuff is out of scope for this answer.

\$\endgroup\$
1
  • 2
    \$\begingroup\$ Also worth noting that it can be more work to keep track of what has or hasn't changed, current and previous states, and all of the comparisons involved than it is to just blast out the entire scene from fresh with none of that work needed. \$\endgroup\$ Commented Dec 1, 2018 at 13:03

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.