Search code examples
c++sdl-2

SDL2 Window Only Shows Black Background


I'm starting a new project in SDL2 and as I'm still trying out different architectural approaches I usually start out by bringing up a white window to confirm that the new approach I'm trying out satisfies at least the bare minimum to get started with SDL2.

This time, I wanted to try wrapping my application into a separate Application class so as to unclutter main, like so:

#include <SDL2/SDL.h>
#include <stdio.h>
#include <string>

#include "HApplication/HApplication.h"


//Screen dimension constants
const int SCREEN_WIDTH = 640;
const int SCREEN_HEIGHT = 480;

int main(int argc, char *argv[])
{
   
    HApplication application = HApplication( SCREEN_WIDTH, SCREEN_HEIGHT );

    bool hasStarted  = application.checkRunning();
    
    
    if ( hasStarted ){

        application.run();
    
    }
    else{
        
        std::string msg = "Application failed to initialize.";
        SDL_LogError( SDL_LOG_CATEGORY_ERROR, msg.c_str() );

    }

    // add error codes
    return 0;

}

Now, the run method in HApplication is meant to reflect the main loop until the user exits. For test purposes, I'd just like to get two lines crossing in the middle on a white background. After initializing SDL, the window, and the renderer, which all work out fine, I'm presented with a window filled completely back, although I've used very similar code successfully before:

void HApplication::run()
{
    // while user doesn't quit, keep going
    bool userQuit = false;

    SDL_Event e

    while( !userQuit )
    {
        // handle queued events
        while ( SDL_PollEvent( &e ) != 0 )
        {
            if ( e.type == SDL_QUIT )
            {
                userQuit = true;
            }
        }

        

        // clear screen
        
        SDL_SetRenderDrawColor( appRenderer, 255, 255, 255, 255);
        SDL_RenderClear( appRenderer );

        // draw cross
        SDL_SetRenderDrawColor( appRenderer, 0, 0, 0, 255 );
        SDL_RenderDrawLine( appRenderer, 0, screenHeight/2, screenWidth, screenHeight/2);
        
        SDL_SetRenderDrawColor( appRenderer, 0, 0, 0, 255 );
        SDL_RenderDrawLine( appRenderer, screenWidth/2 , 0, screenWidth/2, screenHeight);
        
        // update screen with new scene 
        SDL_RenderPresent( appRenderer );
        SDL_UpdateWindowSurface( appWindow );
    }

    close();
}

I'm not quite sure why this happens, especially since I can see what I want stepping through the loop step-by-step using the debugger. I am quite honestly pretty much at a loss at where to even start.

I tried looking on Google and Stackoverflow for similar questions. However, these were mostly addressing problems with loading textures, which I haven't even gotten to yet. If possible, I would like to keep a separate class handling game logic and resources.

EDIT: It seems like I needed to get rid of SDL_UpdateWindow. However, I'm not quite sure why. If anyone has an explanation, I'd be happy to hear!


Solution

  • SDL has both a CPU rendering API and a GPU one.

    Everything that works with a SDL_Renderer belongs to the GPU API. For example, you can make a SDL_Texture and use SDL_RenderCopy to render it. The final step is to call SDL_RenderPresent so that everything that was rendered gets displayed.

    SDL_UpdateWindowSurface is part of the CPU API. To use this API, you can for example draw to a SDL_Surface and then use SDL_BlitSurface with SDL_GetWindowSurface to render to the window's surface. The final step is to call SDL_UpdateWindowSurface to display the changes, which is the equivalent to SDL_Flip in SDL 1.2.

    In short: after the SDL_RenderPresent call, you get what you wanted, but after the SDL_UpdateWindowSurface call, you overwrite that with the CPU window surface which is probably initialized to black. Just remove that SDL_UpdateWindowSurface call and use the GPU API only.