Search code examples
sdlsdl-2

How to copy a texture to another texture without pointing to the same texture


SDL_Texture *screen = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_RGBA8888,
                               SDL_TEXTUREACCESS_TARGET, 800, 800);

I want to copy this screen texture to another texture called temp .

I tried the following code SDL_Texture *temp = screen; but when I changed temp , screen was also changed since they point to the same memory address.

Is there any way to copy the texture without changing the source texture?


Solution

  • The solution (although flawed, see below)

    You can use the following:

    SDL_Texture* DuplicateTexture(SDL_Texture* tex, SDL_Renderer* renderer) {
        Uint32 format;
        int w, h;
        SDL_BlendMode blendmode;
        SDL_Texture* renderTarget;
        SDL_Texture* newTex;
    
        // Get all properties from the texture we are duplicating
        SDL_QueryTexture(tex, &format, NULL, &w, &h);
        SDL_GetTextureBlendMode(tex, &blendmode);
    
        // Save the current rendering target (will be NULL if it is the current window)
        renderTarget = SDL_GetRenderTarget(renderer);
    
        // Create a new texture with the same properties as the one we are duplicating
        newTex = SDL_CreateTexture(renderer, format, SDL_TEXTUREACCESS_TARGET, w, h);
    
        // Set its blending mode and make it the render target
        SDL_SetTextureBlendMode(newTex, SDL_BLENDMODE_NONE);
        SDL_SetRenderTarget(renderer, newTex);
    
        // Render the full original texture onto the new one
        SDL_RenderCopy(renderer, tex, NULL, NULL);
    
        // Change the blending mode of the new texture to the same as the original one
        SDL_SetTextureBlendMode(newTex, blendmode);
    
        // Restore the render target
        SDL_SetRenderTarget(renderer, renderTarget);
    
        // Return the new texture
        return newTex;
    }
    

    Basically, this function creates a new texture with the same properties as the old one, and sets the new texture as the render target. Then it renders the old texture onto it, and sets the render target back to what it was.

    Its flaws

    Unfortunately, this is as close as you can get, and it features the following issue:

    • Pixel data of the new texture might not be 100% the same as the old one due to how texture renders are computed
    • The resulting texture will be in SDL_TEXTUREACCESS_TARGET access mode. It is mandatory to be able to render other textures onto it, and at the time of writing, there are no way to change an SDL_Texture's access mode after it has been created.
    • This might not be supported by all renderers, see the documentation here (archive), that says to check the SDL_RENDERER_TARGETTEXTURE bit in the flags of your renderer's SDL_RendererInfo to see if render targets are supported.

    Why these flaws can't be fixed

    An SDL_Texture, according to the documentation (archive), is:

    A structure that contains an efficient, driver-specific representation of pixel data.

    Which basically means that these are NOT supposed to be messed with. Once you create an SDL_Texture, either you render it, or you render things onto it. That's it.

    On the other hand, check out the documentation for SDL_Surface (archive):

    A structure that contains a collection of pixels used in software blitting.

    These ones are made to be messed with. They are handled by software and exist for the sole and only reason of you, the programmer, to do all sorts of things with it, like editing its pixels, blitting it on other surfaces, etc.

    This is what you should focus on: if you want to edit pixel data or do any sort of modification to something that you then plan to render on screen, then do it in an SDL_Surface. And only when you are done making your edits, convert the SDL_Surface to a SDL_Texture using the SDL_CreateTextureFromSurface (archive) function.

    Besides, as I mentionned, you can blit surfaces on top of other surfaces, just like you can render textures on top of other textures. So it's not like you'd loose anything by using surfaces, besides some performance of course, as SDL_Textures are hardware-accelerated whereas SDL_Surfaces aren't.

    If you want to go more technical about this, please give a look at the excellent answer to What is the point of an SDL2 Texture?

    In the end, the real, flawless solution is not to duplicate SDL_Textures.

    So make sure that if you do it anyway, it is actually justified and only way to make your project work.