skip to Main Content

I’ve been using SDL2 to make a simple game for a few months. I recently tried to add lighting, but when I try and render the lights or any other layers, the screen is just black.

I’ve tried the same code on a different testing project, and it worked. I can’t render png’s either anymore, except sometimes I can. I have no idea what’s causing the problem.

This is how my surfaces are initialized in both my main code and my testing code (just simple SDL_Texture*’s)

this->background = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET, this->dimensions.w, this->dimensions.h);

this->lightLayer = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET, this->dimensions.w, this->dimensions.h);
SDL_SetTextureBlendMode(lightLayer, SDL_BLENDMODE_MOD);

this->resultLayer = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET, this->dimensions.w, this->dimensions.h);
SDL_SetTextureBlendMode(resultLayer, SDL_BLENDMODE_BLEND);

SDL_SetRenderDrawColor(this->renderer, 0x00, 0x00, 0x00, 0xff);

My render function (this is where the problem is)

// Not using lightLayer until I get the background working
SDL_SetRenderTarget(this->renderer, this->resultLayer);
SDL_RenderClear(this->renderer);

SDL_RenderCopy(this->renderer, this->background, NULL, &this->dimensions);
// SDL_RenderCopy(this->renderer, this->lightLayer, NULL, &this->dimensions);

SDL_SetRenderTarget(this->renderer, NULL);
SDL_RenderCopy(this->renderer, this->resultLayer, NULL, &this->dimensions);
SDL_RenderPresent(this->renderer);

SDL_RenderClear(this->renderer);

SDL_SetRenderTarget(this->renderer, this->background);
SDL_RenderClear(this->renderer);

// SDL_SetRenderTarget(this->renderer, this->lightLayer);
// SDL_RenderClear(this->renderer);

Where my background is rendered. This works fine if I set the render target to NULL (The render window), but if I render to background the screen just appears black, because background isn’t being rendered.

void Game::renderSprite(Entity& entity, SDL_Texture* renderSurface)
{
    SDL_SetRenderTarget(this->renderer, this->background); // If I set the second argument to null, it works fine

    //std::cout << "Rendered " << entity.type() << " at " << entity.getCoords().x << ", " << entity.getCoords().y << "n";
    SDL_Rect src;
    src.x = entity.getSpriteSheetRect().x;
    src.y = entity.getSpriteSheetRect().y;
    src.w = entity.getSpriteSheetRect().w;
    src.h = entity.getSpriteSheetRect().h;

    SDL_Rect dest;
    dest.x = entity.getDimensions().x;
    dest.y = entity.getDimensions().y;
    dest.w = entity.getDimensions().w;
    dest.h = entity.getDimensions().h;

    SDL_RenderCopy(this->renderer, entity.getTexture(), &src, &dest);
}

And this is my main loop that calls the functions

// Renders all the tiles to the screen
for (Chunk& chunk : *renderVec)
{
    for (Tile& tile : chunk.getTiles())
    {
        game.renderSprite(tile, game.background);
    }
}

...

game.present();

This is my testing code that works fine. There are some inconsistencies between the testing code, and my actual code, but that’s because of debugging. I have copy-pasted the testing code in and it still doesn’t work.

SDL_Texture* bgTexture = loadTexture(renderer, "game.png");

// light spot
SDL_Texture* light = loadTexture(renderer, "spot.png");
// layers
SDL_Texture* background = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET, 640, 480);
SDL_Texture* lightLayer = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET, 640, 480);
SDL_SetTextureBlendMode(lightLayer, SDL_BLENDMODE_MOD);
SDL_Texture* resultLayer = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET, 640, 480);
SDL_SetTextureBlendMode(resultLayer, SDL_BLENDMODE_BLEND);

SDL_Rect spot1 = { 10, 10, 200, 200 };

while (quit != 1)
{
    // Rendering sprites
    // Background
    SDL_SetRenderTarget(renderer, background);
    SDL_RenderCopy(renderer, bgTexture, NULL, NULL);

    // Lights
    SDL_SetRenderTarget(renderer, lightLayer);
    SDL_Rect spot = { 640, 360, 300, 300 };
    SDL_RenderCopy(renderer, light, NULL, &spot); // Middle-ish



    // Rendering everything
    SDL_SetRenderTarget(renderer, resultLayer);
    // Background
    SDL_RenderCopy(renderer, background, NULL, &dimensions);
    // Lights
    SDL_RenderCopy(renderer, lightLayer, NULL, &dimensions);

    // Putting everything on the screen
    SDL_SetRenderTarget(renderer, NULL);
    SDL_RenderCopy(renderer, resultLayer, NULL, &dimensions);

    // Presenting
    SDL_RenderPresent(renderer);



    // Clearing render targets; which also draws the desired color
    // Window
    SDL_RenderClear(renderer);

    // Background
    SDL_SetRenderTarget(renderer, background);
    SDL_SetRenderDrawColor(renderer, 0x00, 0x00, 0x00, 0xff);
    SDL_RenderClear(renderer);

    // Shadow/light layer        Set to SDL_BLENDMODE_MOD
    SDL_SetRenderTarget(renderer, lightLayer);
    SDL_SetRenderDrawColor(renderer, 0x00, 0x00, 0x00, 0xff); // Alpha value doesn't matter
    // any color besides black is some degree of transparent. Eg. Blue is seen below
    //SDL_SetRenderDrawColor(renderer, 50, 69, 155, 255); // More transparent color
    // Fill screen with color; Doesn't matter which one
    //SDL_RenderFillRect(renderer, NULL);
    SDL_RenderClear(renderer); // Prefered: Can clear the surface and set color, and is platform independant

    // Result layer              Set to SDL_BLENDMODE_BLEND
    SDL_SetRenderTarget(renderer, resultLayer);
    SDL_SetRenderDrawColor(renderer, 0x00, 0x00, 0x00, 0xff);
    SDL_RenderClear(renderer);

I’m using visual studio 2022 with MSVC compiler, and C++20.

2

Answers


  1. Chosen as BEST ANSWER

    I just changed &this->dimensions to NULL, and now the background is rendering. I don't know why that was a problem.


  2. I would recommend going through the SDL_SetRenderTarget() documentation but also this SO answer: https://stackoverflow.com/a/21007477/8204677 which might clear the questions you are having.

    Your render function

    // Not using lightLayer until I get the background working
    SDL_SetRenderTarget(this->renderer, this->resultLayer);
    SDL_RenderClear(this->renderer);
    
    SDL_RenderCopy(this->renderer, this->background, NULL, &this->dimensions);
    // SDL_RenderCopy(this->renderer, this->lightLayer, NULL, &this->dimensions);
    
    SDL_RenderPresent(this->renderer);
    
    SDL_SetRenderTarget(this->renderer, this->background);
    SDL_RenderClear(this->renderer);
    
    // SDL_SetRenderTarget(this->renderer, this->lightLayer);
    // SDL_RenderClear(this->renderer);
    

    Where my background is rendered. This works fine if I set the render
    target to NULL (The render window), but if I render to background the
    screen just appears black, because background isn’t being rendered.

    To answer this specific problem, I believe you need to understand how the rendering works. In your function to render, you claim that you are trying to render your background but it doesn’t work. I suppose you are talking about the SDL_RenderPresent(this->renderer); after your copy your background with SDL_RenderCopy(). Since you set the rendertarget to this->resultlayer earlier with SDL_SetRenderTarget() you aren’t rendering to the window anymore. To do this according to the documentation you need to:

    To stop rendering to a texture and render to the window
    again, call this function with a NULL texture.

    which I believe you mentioned yourself. Similarly to what you do in your "testing code" you can do this with the resulting layer if you would want the result layer to be presented to the window:

    SDL_SetRenderTarget(renderer, NULL);
    SDL_RenderCopy(renderer, resultLayer, NULL, &dimensions);
    

    I suppose the summary / TLDR would be: You are rendering to a texture and not the window which is why you experience a black screen.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search