Help, I can't figure out how to render a texture onto a texture

 SDL_Texture *render() {

    renderTexture =
        SDL_CreateTexture(GameManager::renderer, SDL_PIXELFORMAT_RGBA8888,
                          SDL_TEXTUREACCESS_TARGET, box.size.x, box.size.y);

    SDL_Texture *tileTexture =
        ResourceManager::getInstance(GameManager::renderer).getTexture(image);

    SDL_SetRenderTarget(GameManager::renderer, renderTexture);

    for (float y = 0; y < box.size.y; y += tileSize) {
      SDL_Rect boxRect = SDL_Rect(0, y, tileSize, tileSize);
      SDL_RenderCopy(GameManager::renderer, tileTexture, &srcRect, &boxRect);
    }

    SDL_SetRenderTarget(GameManager::renderer, nullptr);

    return renderTexture;
  }

Does anyone see what I’m doing wrong here? I’m just trying to render textures onto textures and I can’t get anything to work, I’ve even tried rendering Filled Rects to it and it still does nothing. I can confirm that returning a texture pointer makes it render because things are drawn if I return tileTexture instead of renderTexture. I’ve also tried turning on blending on the renderTexture as well as trying to expand its size

First, there’s gonna be a performance hit to creating a new texture every frame. Instead create renderTexture at program start (or wherever appropriate) and reuse it.

Second, are you sure your rects are a sensical size? Where are box, srcRect, tileSize defined? Make sure they’re the size you expect them to be.

Third, you should set the viewport every time you change render targets. When you change to renderTexture, set the viewport to the size of the render texture, and when you change back to the default render target, set the viewport to whatever size it is. SDL_RenderSetViewport()

Lastly, you aren’t checking if your call to SDL_CreateTexture() succeeds.

1 Like

Here are some classes

struct TileRaw {
  std::string image;
  SDL_Rect srcRect;
  Box box;
};

struct TileGroup {
  TileGroup(){};

  TileGroup(TileRaw _tileRaw, Box newBox) {
    image = _tileRaw.image;
    srcRect = _tileRaw.srcRect;
    tileSize = _tileRaw.box.size.x;

    box = newBox;
  }

  ~TileGroup() { 
    if (renderTexture != nullptr) {
      SDL_DestroyTexture(renderTexture);
    }
  }

  SDL_Texture *render();

  }

  std::string image;
  SDL_Rect srcRect;
  Box box;
  int tileSize;

private:
  SDL_Texture *renderTexture = nullptr;
};

I’ve check those variables and I believe they are all correct

Ill try the viewport in a sec but what do you mean by checking for success? If your talking about using SDL_GetError, then yes that has been tried.

Also the render method isn’t being called every frame, its only being called once and the return texture is being drawn every frame

Calling SDL_GetError() is itself not the way to check for errors; a few SDL functions set the error string even when no error occurs. SDL_GetError() is just to get more detail about what went wrong after an SDL call fails.

So check to see if renderTexture returned nullptr or not. And if it is returning nullptr (the texture couldn’t be created) then you would call SDL_GetError() to find out why.

1 Like
 renderTexture =
        SDL_CreateTexture(GameManager::renderer, SDL_PIXELFORMAT_RGBA8888,
                          SDL_TEXTUREACCESS_TARGET, box.size.x, box.size.y);

    if (renderTexture != nullptr) {
      std::cout << "Real\n";
    }

I can confirm renderTexture is Not a nullptr

I’ve never known that to be necessary. I’m changing render targets all the time, on a range of different platforms (desktop, mobile, web), and everything works as I would expect without ever touching the viewport.

Looking at the code, SDL_SetRenderTarget() does indeed change the viewport accordingly. Since GPU APIs (OpenGL, Metal, Vulkan) require you to do it yourself after changing framebuffer objects, I’ve always just manually called SDL_SetRenderTarget() since the docs don’t mention it handling the viewport for you.