Is possible to create ambient light in SDL2?

This is something I’ve been trying to do for really long long time, this last few days I managed to get to what I want (see screenshot below).

My next question is how do you blend or tint the mask, say I want the black portion to be blend as a blue-purple-ish to give more of a night ambient rather than just being super dark with a candlelight. The screenshot in the bottom was done by changing the render draw color to something else make it it look transparent and blend into it, but it never goes to tint the actual color selected.

Here is an example in pokemon second generation, it just a purplish tint that blends with actual color instead of just an overlay color on top. I have tried putting an purple texture on top with blend mode, it’s too far from this, and I’m not expecting the same.

pokemon

Using a white painted brush on a black background I was able to create that effect, and it looks “tinted” when using different colors instead of white.

Here are the light spots I used

light-white light-yellow light-yellow-small

Changing the render draw color looks like this:
SDL_SetRenderDrawColor(renderer, 0x36, 0x45, 0x9b, 0xff);


At the end of the day I want to be able to use different color to simulate different time of the day, not like this, but you get an idea in this link: https://www.gamasutra.com/blogs/SvyatoslavCherkasov/20181023/329151/Graveyard_Keeper_How_the_graphics_effects_are_made.php

In summary:

  • How do I change the black color to be transparent while having the “bright” spot?

  • How I blend another color or tint a texture to look like the screenshot of pokemon or the last game linked to gamasutra?

  • Or How do I create a tint in the light black color that blends to the game background to look like tint?

  • Is possible to do all this to create ambient light?

    #include <SDL2/SDL.h>
    #include <SDL2/SDL_image.h>
      
    int main(int argc, char ** argv)
    {
      SDL_Event event;
      int quit = 0;
    
      SDL_Init(SDL_INIT_VIDEO);
    
      SDL_Window * window = SDL_CreateWindow(
              "2D Light test",
              SDL_WINDOWPOS_UNDEFINED,
              SDL_WINDOWPOS_UNDEFINED,
              640,
              480,
              0
      );
      SDL_Renderer * renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_PRESENTVSYNC);
      SDL_SetRenderDrawBlendMode(renderer, SDL_BLENDMODE_BLEND);
    
      // layers
      SDL_Texture * backgroundLayer = 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_Texture * resultLayer = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET, 640, 480);
    
      // "game" graphics rendered
      SDL_Surface * bgSurface = IMG_Load("game.jpg");
      SDL_Texture * bgTexture = SDL_CreateTextureFromSurface(renderer, bgSurface);
      SDL_FreeSurface(bgSurface);
    
      // light spot
      SDL_Surface * lightSurface = IMG_Load("spot.jpg");
      SDL_Texture * lightTexture = SDL_CreateTextureFromSurface(renderer, lightSurface);
      SDL_FreeSurface(lightSurface);
    
      while (quit != 1)
      {
          while( SDL_PollEvent(&event) != 0 )
          {
              switch (event.type)
              {
                  case SDL_QUIT:
                      quit = 1;
                      break;
              }
          }
    
          SDL_SetRenderDrawColor( renderer, 0x00, 0x00, 0x00, 0x00 );
          SDL_RenderClear( renderer );
    
    
          // fake game tiles, objects, players rendering
          SDL_SetRenderTarget( renderer, backgroundLayer );
          SDL_SetRenderDrawColor( renderer, 0x00, 0x00, 0x00, 0x00 );
          SDL_RenderClear( renderer );
    
          SDL_Rect gameRect = {0, 0, 640, 480};
          SDL_RenderCopy(renderer, bgTexture, NULL, &gameRect);
    
          SDL_SetRenderTarget(renderer, NULL);
    
    
          // draw light points
          SDL_SetRenderTarget(renderer, lightLayer);
          SDL_SetTextureBlendMode(lightLayer, SDL_BLENDMODE_MOD);
          SDL_SetRenderDrawColor(renderer, 0x00, 0x00, 0x00, 0x00);
          // change the black color to a more transparent one
          // SDL_SetRenderDrawColor(renderer, 0x36, 0x45, 0x9b, 0xff);
          // ----
          SDL_RenderClear(renderer);
    
          SDL_Rect spot1 = {10, 10, 200, 200};
          SDL_Rect spot2 = {240, 240, 200, 200};
    
          SDL_RenderCopy(renderer, lightTexture, NULL, &spot1);
          SDL_RenderCopy(renderer, lightTexture, NULL, &spot2);
    
          SDL_SetRenderTarget(renderer, NULL);
    
          // merge all layers
          SDL_SetRenderTarget(renderer, resultLayer);
    
          SDL_SetRenderDrawColor(renderer, 0x00, 0x00, 0x00, 0x00);
          SDL_RenderClear(renderer);
    
          SDL_SetTextureBlendMode(resultLayer, SDL_BLENDMODE_BLEND);
          SDL_RenderCopy(renderer, backgroundLayer, NULL, &gameRect);
    
          SDL_RenderCopy(renderer, lightLayer, NULL, &gameRect);
    
          SDL_SetRenderTarget(renderer, NULL);
          SDL_RenderCopy(renderer, resultLayer, NULL, &gameRect);
    
          SDL_RenderPresent(renderer);
      }
    
      SDL_DestroyTexture(bgTexture);
      SDL_DestroyTexture(lightTexture);
      SDL_DestroyRenderer(renderer);
      SDL_DestroyWindow(window);
      SDL_Quit();
    
      return 0;
     }
    

I have played with different options of blending and creating custom blendmode with all the possible combinations I could come up.

what about rendering your lights as SDL_BLENDMODE_ADD to a texture with a blend mode set to SDL_BLENDMODE_MOD then render that on top of the scene?

SDL_Texture lights; /* blend mode as SDL_BLENDMODE_ADD, imported from a file or something*/

SDL_Texture shadow; /* blend mode as SDL_BLENDMODE_MOD, should be created with SDL_CreateTexture with SDL_TEXTUREACCESS_TARGET */

/*rendering the shadow*/ 

SDL_SetRenderTarget(shadow);

SDL_SetRenderColor(0, 0, 0, 255);  /* put your desired tint , (the alpha value has no effect here) */

SDL_RenderFillRect(nullptr); /* draw the color to the entire shadow*/

SDL_RenderCopy(lights); /* your spotlights */

SDL_SetRenderTarget(0) /* set the render back to your scene*/;

SDL_RenderCopy(shadow); /* shadow */

SDL_RenderPresent(); /* show everything */

example photos
tint color (60, 0, 100, 255) with lights

tint color (0, 0, 0, 255) with lights

normal scene

tint color (60, 0, 100, 255) no lights

is this what you wanted?

Thank you very much @obeah, this is exactly what I wanted, after I read your example I had some issues that the color wasn’t the color of the tint, but then I realized your image is black and white, and that act nicely tinting the color.

Using tint color (60, 0, 100, 255)

Using tint color (0, 0, 255, 255)

Looking only good when the color blending match with the colorful background otherwise it doesn’t paint the expected color.

Using the same image black and white the result looks way better

Using tint color (60, 0, 100, 255)

Using tint color (0, 0, 255, 255)

The only drawback now, it’s that the light spots are black and white, I tried using a yellow spot instead of a white, but still not as expected with the original colors. I also tried to blend the original colored picture on top (MUL, ADD, MOD, BLEND), but the result was the same as without using the black and white image.

This is an extra question, do you know if there’s any techniques for this.

Again thank you very much this is going to the direction I wanted.

1 Like

I am not entirely sure how it works, but from the docs, you can write your own blend functions.

I tried blend mode as SDL_ BLENDMODE_MUL, it seems to work. Can you show me the full source code in your solution?