5
\$\begingroup\$

Simply put: What is the simplest way to render an image to two different sdl2 windows?

I'm pretty new to SLD2, but I have a nice little level editor working. I then decided to move the area with edit tools to a separate window. I immediately got the following error:

Texture was not created with this renderer.

Alas, it looks like each window needs to have its own SDL_Renderer, and each renderer needs to create its own textures for the images I want to display.

IMG_LoadTexture() needs a renderer and will only render the resulting texture to that renderer.

SDL_CreateRenderer() then needs a window as a parameter and doesn't seem to be able to ever render to another output window.

So does this really mean I have to create separate textures of each of my images for each and every renderer/window? Or is there a way to load graphics into textures that can be used by any renderer, or on any window?

\$\endgroup\$
7
\$\begingroup\$

All right, so this is an interesting topic. As per this forum topic, this isn't natively supported by SDL.

However, with some minor tinkering I was able to setup a quick and dirty demo that loads a texture just once, for one rendering. I'll go through my setup step by step. Do note that you probably want to change most of the hardcoded stuff (such as the color masks for the surface) to dynamically chosen ones. These values work for me.

  1. You setup your windows and renderers:

    SDL_Window* window1 = SDL_CreateWindow("Window 1", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 640, 480, 0);
    SDL_Window* window2 = SDL_CreateWindow("Window 2", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 640, 480, 0);
    
    SDL_Renderer* renderer1 = SDL_CreateRenderer(window1, -1, 0);
    SDL_Renderer* renderer2 = SDL_CreateRenderer(window2, -1, 0);
    
  2. You load your texture for your first, or main, renderer:

    SDL_Texture* texture1 = IMG_LoadTexture(renderer1, "path_here.png");
    
  3. Now, this is where stuff gets interesting. You create a streaming texture for the second renderer and a target texture for the first:

    SDL_Texture* texture2 = SDL_CreateTexture(renderer2, SDL_GetWindowPixelFormat(window1), SDL_TEXTUREACCESS_STREAMING, 640, 480);
    SDL_Texture* target = SDL_CreateTexture(renderer1, SDL_GetWindowPixelFormat(window1), SDL_TEXTUREACCESS_TARGET, 640, 480);
    
  4. Finally, for easier access, we create an SDL_Surface that we'll be using as a buffer.

    SDL_Surface* buffer = SDL_CreateRGBSurface(0, 640, 480, 32, 0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000);
    
  5. Now we are ready to get rendering! Start your rendering with clearing both renderers:

    SDL_RenderClear(renderer1);
    SDL_RenderClear(renderer2);
    
  6. Then comes the interesting stuff: This is where you would render everything you want to display on the second monitor to the render target:

    SDL_SetRenderTarget(renderer1, target);
    SDL_RenderCopy(renderer1, texture1, NULL, NULL);
    SDL_RenderReadPixels(renderer1, NULL, SDL_GetWindowPixelFormat(window1), buffer->pixels, buffer->pitch);
    SDL_SetRenderTarget(renderer1, NULL);
    

    So, we simply set the render target, and draw our loaded texture onto it. After that, as you can see, we read the pixels from the renderer into our buffer surface. This is the real trick of the approach.

  7. Now we just need to pass the data in buffer to the streaming texture we created for the second renderer:

    SDL_UpdateTexture(texture2, NULL, buffer->pixels, buffer->pitch);
    
  8. Then you can render the streaming texture onto the second window:

    SDL_RenderCopy(renderer2, texture2, NULL, NULL);
    
  9. And finally update the displays:

    SDL_RenderPresent(renderer1);
    SDL_RenderPresent(renderer2);
    

Now you've rendered a texture loaded on the main renderer onto your secondary window. It is a little hacky and perhaps a little slow, but for something like a secondary window for a level editor it might be enough. I didn't do any sort of stress-testing for this but both SDL_RenderReadPixels and SDL_UpdateTexture can be a little slow.

In any case, you might want to try this out and see if the performance is good enough for you. Having double textures on the other hand can be tedious and memory intensive, but the performance should be better.

\$\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.