# 2D simulating light sources (subtract a texture from an other)

I want to simulate a night and day cycle with SFML (plain 2D, no shadows). What I want is to get a smooth transition from day to night, and during night having some lights "on".

So the approach I've thought is adding a black layer on top and change its transparency with time, that gives the effect I'm looking for. For adding lights I can crop out circles out of that layer

sf::CircleShape lightCircle(200);
lightCircle.setFillColor(sf::Color(255, 255, 255, 1));

sf::RenderTexture renderTexture;
renderTexture.create(/* view size */);

while (window.isOpen()) {
// ...

// update light
renderTexture.clear(sf::Color::Black);
renderTexture.draw(lightCircle, sf::BlendNone);
renderTexture.display();

// draw
window.clear();
window.draw(sf::Sprite(renderTexture.getTexture()));
window.display();
}


Now, what I would like to do is use my own image instead of a CircleShape. Say a circle or a cone with fading borders, some more realistic than just a circle. Like

I have tried with sf::Image and createMaskFromColor but I'm not able to handle the fading edges.

How can I get that?

Am I in the right path or is there a simpler approach?

• So is your issue that using your own image creates hard edges, instead of smooth, anti-aliased edges? Oct 2 '16 at 13:54
• My image has some transparency (see updated post), my issue is that I don't know how to subtract that image from the renderTexture Oct 2 '16 at 14:28
• I wrote up a general description of how I did this in xna including handling multiple light sources. Might be helpful: gamedev.stackexchange.com/a/22163/5060 Oct 3 '16 at 0:01
• Would it make sense if you drew all lights to a second render target at first (using your first image, but white instead of black) and then mutipying the color of your scene by the r, g or b value of your second render target? Oct 3 '16 at 4:28

## 1 Answer

The trick is defining a custom blend mode that substract the alpha pattern of the image from the render target

sf::BlendMode blendMode(
sf::BlendMode::Factor::Zero,              // color src
sf::BlendMode::Factor::DstColor,          // color dst
sf::BlendMode::Equation::Add,             // color eq
sf::BlendMode::Factor::Zero,              // alpha src
sf::BlendMode::Factor::OneMinusSrcAlpha,  // alpha dst
sf::BlendMode::Equation::Add);            // alpha eq


There might be a more straight forward way of doing this, but this one does the trick.

The code looks something like this

sf::RenderTexture renderTexture;
renderTexture.create(/* view size */);

sf::Texture lightTexture;
if (!lightTexture.loadFromFile("light.png")) {
return 1;
}
sf::Sprite light0(lightTexture);
sf::Sprite light1(lightTexture);

while (window.isOpen()) {
// ...

// update light
renderTexture.clear();
renderTexture.draw(light0, blendMode);
renderTexture.draw(light1, blendMode);
renderTexture.display();
sf::Sprite night(renderTexture.getTexture());

float luminosity = 200.0f;
night.setColor(sf::Color(10.0f, 10.0f, 10.0f, luminosity));

// draw
window.clear();
window.draw(background);
window.draw(night);
window.display();
}