Letting an object render itself gives black screen

Hey guys, I never like my first post anywhere being a cry for help, but here goes! Google returned nothing, so figured I’d ask here.

I’m making an application using SDL2 that’s meant to display graphs in separate windows. To do that, I have a class called figure with the following header:

class figure
{
private:
    short window_width;
    short window_height;
    SDL_Window* window = NULL;
    SDL_Renderer* renderer = NULL;
    SDL_Event fig_handler;
public:
    figure(short fig_typ);
    void render();
    short figure_type;
};

And the following implementation:

figure::figure(short fig_typ)
{
    window_width = 840;
    window_height = 680;
    window = SDL_CreateWindow( "Demo Window", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, window_width, window_height, SDL_WINDOW_SHOWN );
    if (window==NULL)
    {
        std::cout << "Window could not be created! SDL_Error: " << SDL_GetError() << std::endl;
    }

    renderer = SDL_CreateRenderer( window, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC );
    if (renderer==NULL)
    {
        std::cout << "Window could not be created! SDL_Error: " << SDL_GetError() << std::endl;
    }

    // Set default colour to turquise
    SDL_SetRenderDrawColor(renderer, 45, 164, 132, SDL_ALPHA_OPAQUE);

    figure_type = fig_typ;
}

void figure::render()
{
    while (SDL_PollEvent(&fig_handler))
    {
        if (fig_handler.type == SDL_QUIT)
        {
            // Do things here
        }
    }
    SDL_RenderClear(renderer);
    SDL_RenderPresent(renderer);
    SDL_Delay(0);
}

This all works rather well. I can just write while (true){fig1.render();} and a turquoise window will stay up until I close the program. But in my program, I want many of these figures to coexist, and to simplify the process, I decided I would make a new class model to keep track of the figures.

The header:

class model
{
public:
    model();
    void add_figure(short index, short fig_typ);
    bool update();
private:
    std::map<short, figure*> figure_map;
};

The implementation:

model::model()
{
    // Initialize SDL
    if( SDL_Init( SDL_INIT_VIDEO ) < 0 )
    {
        std::cout << "SDL could not initialize! SDL_Error: " << SDL_GetError() << std::endl;
    }
}

void model::add_figure(short index, short fig_typ)
{
    figure tempFigure(fig_typ);
    std::pair<short, figure*> tempPair(index, &tempFigure);
    figure_map.insert(tempPair);
}

bool model::update()
{
    for (std::map<short, figure*>::iterator it = figure_map.begin(); it != figure_map.end(); ++it)
    {
        it->second->render();
    }
    return true;
}

And mysteriously, when I create a model object and give it a figure, and subsequently call while (true) {model_object.update();}, the window turns black. When I delete the event handling from the figure object (like I originally intended), SDL doesn’t even bother to make a nice window: I only get a blurred white or black window, depending on which parts of the handling I delete.

It seems like SDL doesn’t even take the time to nicely render everything. Another StackOverflow-post suggested adding SDL_Delay(0) somewhere along the lines to make SDL catch its breath (as you can see, I put it into figure::render()) but so far it doesn’t make a difference.

What can I do to render my window like it’s supposed to, but still maintain this structure: a structure in which an object calls a function of another object to draw the window.

P.s. I’m working from a laptop with MacOS, and compiling using g++. Oh and thanks in advance ^^

P.s. I’m working from a laptop with MacOS, and compiling using g++. Oh
and thanks in advance ^^

This appears to be a bug in the Mac renderer code; here’s a simplified C
program that exhibits the same problem.

test-multi-renderer.c (1.3 KB)

–ryan.

This appears to be a bug in the Mac renderer code; here’s a simplified C program that exhibits the same problem.

Disregard this; the second SDL_CreateRenderer call in my example used the same window as the first (cut and paste error!). If I change it to window2 it works fine on a Mac.

This was with the latest in Mercurial; it’s possible we fixed something if you’re on an official release. Can you try my test program and see if it works on your system?

Thanks for the help! I ran the code and this is what happens:

  1. The window on bottom (window1 I think) is a nice turquoise.
  2. The window on top (so that has to be window2) is black.

Yesterday I replaced my SDL2.framework with the latest release 2.0.5. Is there anything that could still have me using an old release? This is my terminal command:

g++ main.cpp src/vec2.cpp src/tools.cpp -Wall -I/Library/Frameworks/SDL2.framework/Headers -F/Library/Frameworks -o pt -framework SDL2

Something weird is going on here…

Turns out it was more of a programming mistake than a SDL2-mistake. In model::add_figure() I create a temporary object tempFigure within the scope of the function. I then point at it from a map. Not the smartest thing to do: there is no guarantee that the address will contain a figure object after the function is finished. In this case, the unidentified behaviour expresses itself as a black screen. What works better is to write:

void model::add_figure(short index, short fig_typ)
{
    figure* tempFigure = new figure(fig_typ);
    std::pair<short, figure*> tempPair(index, tempFigure);
    figure_map.insert(tempPair);
}

Using this code, I can make two windows that display the colour turquoise just like I want them to.

In that aspect, the problem is solved. Yet when I use your code, icculus, I still get the same result: one turquoise screen, and one black. Inspired by the solution to my own problem, I decided trying to initialise the objects outside of main() by writing

SDL_Window* window1 = NULL;
SDL_Renderer* renderer1 = NULL;

SDL_Window* window2 = NULL;
SDL_Renderer* renderer2 = NULL;

before the main function. Doesn’t change a thing, however.

So I guess the new question becomes: what’s wrong with icculus’ code? Could it be something wrong with my laptop or implementation of SDL?

The window on top (so that has to be window2) is black.

And to be clear: that was with the fix to the second
SDL_CreateRenderer() call? (the source I posted has window1 in that
call, it should be window2).

–ryan.

Yeah, at the bottom of the while loop now is

SDL_RenderClear(renderer1);
SDL_RenderPresent(renderer1);
SDL_RenderClear(renderer2);
SDL_RenderPresent(renderer2);

Yeah, at the bottom of the while loop now is

I’m sorry, I meant this line…

SDL_Renderer *renderer2 = SDL_CreateRenderer( window1, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC );

…should look like this…

SDL_Renderer *renderer2 = SDL_CreateRenderer( window2, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC );

(note that window1 became window2.)

Whoops, stupid mistake- all is fixed now! Thanks for the help!

1 Like