2
\$\begingroup\$

So I have my class vItem which has a vector (consider elements like layers) of textures, origin rects and destination rects plus other stuff.
Basically whenever I update any of the layers in the vector I redraw everything on an internal texture which is then displayed on the screen, here's the function that draws on the texture:

void vItem::draw(){
    if(sprites.size() <= 0)
        return;

    // This calculates the dimensions of a rectangle big enough to contain every texture
    SDL_Point size = calculateSpriteRect();

    if(size.x <= 0 || size.y <= 0)
        return;

    // If the final texture does not exists or its dimensions are different from the new rectangle I destroy it and recreate it
    if(final_sprite == NULL || size.x != final_sprite_size.x || size.y != final_sprite_size.y){
        if(final_sprite != NULL)
            SDL_DestroyTexture(final_sprite);
        final_sprite = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET, size.x, size.y);
        SDL_SetTextureBlendMode(final_sprite, SDL_BLENDMODE_BLEND);
        final_sprite_size = {size.x, size.y};
    }

    SDL_RenderPresent(renderer);
    SDL_SetRenderTarget(renderer, final_sprite);
    SDL_SetRenderDrawColor(renderer, 0, 0, 0, 0);
    SDL_RenderClear(renderer);
    for(int i = 0; i < sprites.size(); i++){
        SDL_SetTextureAlphaMod(sprites[i].sprite, sprites[i].alpha);
        SDL_RenderCopy(renderer, sprites[i].sprite, &sprites[i].source, &sprites[i].bounds);
    }   
    SDL_RenderPresent(renderer);
    SDL_SetRenderTarget(renderer, NULL);
}

The problem comes after this function: I have a child class of vItem called vButton where I have two layers of text (one normal and the other on for when the mouse is over the button), and when I update alpha values of the layers to hide one level and show the other one draw() is called. This transition causes an instant flickering (black background right before drawing).
When I removed vSync I noticed that this wasn't happening anymore, but I need vSync.

UPDATE:
Ok... Apparently if I remove both SDL_RenderPresent(renderer); the flickering is gone and everything is rendering correctly, but I can't understand why. This is the final function:

void vItem::draw(){
    if(sprites.size() <= 0)
        return;

    // This calculates the dimensions of a rectangle big enough to contain every texture
    SDL_Point size = calculateSpriteRect();

    if(size.x <= 0 || size.y <= 0)
        return;

    // If the final texture does not exists or its dimensions are different from the new rectangle I destroy it and recreate it
    if(final_sprite == NULL || size.x != final_sprite_size.x || size.y != final_sprite_size.y){
        if(final_sprite != NULL)
            SDL_DestroyTexture(final_sprite);
        final_sprite = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET, size.x, size.y);
        SDL_SetTextureBlendMode(final_sprite, SDL_BLENDMODE_BLEND);
        final_sprite_size = {size.x, size.y};
    }

    //SDL_RenderPresent(renderer);
    SDL_SetRenderTarget(renderer, final_sprite);
    //SDL_SetRenderDrawColor(renderer, 0, 0, 0, 0);
    //SDL_RenderClear(renderer);
    for(int i = 0; i < sprites.size(); i++){
        SDL_SetTextureAlphaMod(sprites[i].sprite, sprites[i].alpha);
        SDL_RenderCopy(renderer, sprites[i].sprite, &sprites[i].source, &sprites[i].bounds);
    }   
    //SDL_RenderPresent(renderer);
    SDL_SetRenderTarget(renderer, NULL);
}

How can the renderer keep information about the texture on texture rendering and texture on screen rendering at the same time (since I have only one SDL_RenderPresent() left at the end of my game loop)? Is it meant to work like that?

\$\endgroup\$
  • \$\begingroup\$ You are calling SDL_RenderPresent twice with a SDL_RenderClear in between, is that intentional? \$\endgroup\$ – Andy M Nov 6 '15 at 18:58
  • \$\begingroup\$ @AndyM I use that renderer to draw textures to screen too, so if there are any, I render the renderer then clear it, draw on texture and render it again \$\endgroup\$ – Xriuk Nov 8 '15 at 17:00
1
\$\begingroup\$

I figured this out! So I was working on my SDL2 Rendering code using a buffer texture with SDL_TEXTUREACCESS_TARGET which showed the same problem as yourself (aka did not work) and it looked like this:

if(SDL_RenderClear(Global->renderer))
{
    /*  Error... omitted for readability... */
}

/* render all my textures, such as cars, ships, anything on the window... */

SDL_RenderPresent(Global->renderer);

setRendererTarget(NULL);

if(SDL_RenderCopy(Global->renderer, Global->textureBuffer, NULL, NULL))
{
    /*  Error... omitted for readability... */
}

SDL_RenderPresent(Global->renderer);

if(SDL_RenderClear(Global->renderer))
{
    /*  Error... omitted for readability... */
}

setRendererTarget(Global->textureBuffer);

The gist of my and yours to an extent code was:

  • Render Clear
  • Render all textures to screen
  • Render Present
  • Switch Render Target to Window
  • Render Copy Texture Buffer to Window
  • Render Present
  • Render Clear
  • Switch Render Target back to Texture Buffer

I've highlighted in bold the issue. We're clearing the screen AFTER a Render Present not BEFORE. But doesn't the game loop just clear at the top of the loop, rather than at the bottom?

while(1)
    clear?
    Render Stuff...
    clear?

No, because at the end of a game loop is an SDL_Delay, which means in a 1/60th of a second, the screen is cleared, rather than AFTER the delay, which is 1 game tick and nothing is presented on the screen for "real time".

while(1)
    clear!
    Render Stuff...
    SDL_Delay!

SDL_RenderClear clears the target (not internal backbuffer). The implementations for this is system Dependant here: https://github.com/spurious/SDL-mirror/search?utf8=%E2%9C%93&q=RenderClear+%3D+&type=

So the actual list of operations needs to be:

  • Render Clear
  • Render Copy
  • Render Present
  • FPS Delay

For any rendering. Case closed!

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.