Friday, June 23, 2017

sdl2 - Render to texture and then to screen cause flickering


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?




No comments:

Post a Comment

Simple past, Present perfect Past perfect

Can you tell me which form of the following sentences is the correct one please? Imagine two friends discussing the gym... I was in a good s...