I went ahead and created a minimal code example. It is still fairly large but you can see what is going on.
What I want is to have the lighting to only affect the rgb of the texture it is rendered to and not the alpha. In this example, that would mean that you would not see the red and blue checkers behind the green strip and circle. I'm not sure if I can achieve this simply with glBlendFunc() and maybe I need to use a fragment shader? GL coding is definitely a weakness of mine.
#include <SFML/Graphics.hpp>
#ifdef __APPLE__
#include <OpenGL/gl.h>
#else
#include <GL/GL.h>
#endif
void renderLight(sf::RenderTexture* target, sf::RenderTexture& lightTexture) {
sf::Vector2f viewSize(target->getSize());
sf::Vector2f viewCenter(viewSize.x / 2.0f, viewSize.y / 2.0f);
viewCenter.y = viewSize.y - viewCenter.y;
sf::Vector2f lowerBounds(viewCenter.x - viewSize.x / 2, viewCenter.y - viewSize.y / 2);
sf::Vector2u viewSizeui(static_cast<unsigned int>(viewSize.x), static_cast<unsigned int>(viewSize.y));
glDisable(GL_TEXTURE_2D);
lightTexture.setActive();
glViewport(0, 0, viewSizeui.x, viewSizeui.y);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
// Upside-down, because SFML is pro like that
glOrtho(0, viewSize.x, 0, viewSize.y, -100.0f, 100.0f);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
sf::Color ambientColor(255, 255, 255, 255);
lightTexture.clear(ambientColor);
glColor4b(ambientColor.r, ambientColor.g, ambientColor.b, ambientColor.a);
glBlendFunc(GL_ONE, GL_ZERO);
// Clear with quad, since glClear is not working for some reason... if results in very ugly artifacts
glBegin(GL_QUADS);
glVertex2f(0.0f, 0.0f);
glVertex2f(viewSize.x, 0.0f);
glVertex2f(viewSize.x, viewSize.y);
glVertex2f(0.0f, viewSize.y);
glEnd();
glEnable(GL_TEXTURE_2D);
glLoadIdentity();
glBlendFunc(GL_ONE, GL_ZERO);
glColor4f(0.0f, 0.0f, 0.0f, 1.0f);
glBegin(GL_QUADS);
glVertex2f(0.0f, 0.0f);
glVertex2f(viewSize.x, 0.0f);
glVertex2f(viewSize.x, viewSize.y);
glVertex2f(0.0f, viewSize.y);
glEnd();
glLoadIdentity();
glTranslatef(-lowerBounds.x, -lowerBounds.y, 0.0f);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glBegin(GL_QUADS);
const float height = 6.0f;
for (int i = 0; i < 100; ++i) {
const float value = i * 0.01f;
glColor4f(value, value, value, value);
glVertex2f(0.0f, i * height);
glVertex2f(viewSize.x, i * height);
glVertex2f(viewSize.x, (i + 1) * height);
glVertex2f(0.0f, (i + 1) * height);
}
glEnd();
lightTexture.display();
target->resetGLStates();
// Translate by negative camera coordinates. glLoadIdentity will not work, probably
// because SFML stores view transformations in the projection matrix
glTranslatef(lowerBounds.x, -lowerBounds.y, 0.0f);
lightTexture.getTexture().bind();
//Set up color function to multiply the existing color with the render texture color
glBlendFunc(GL_DST_COLOR, GL_ZERO);
target->setActive();
glBegin(GL_QUADS);
glTexCoord2i(0, 0); glVertex2f(0.0f, 0.0f);
glTexCoord2i(1, 0); glVertex2f(viewSize.x, 0.0f);
glTexCoord2i(1, 1); glVertex2f(viewSize.x, viewSize.y);
glTexCoord2i(0, 1); glVertex2f(0.0f, viewSize.y);
glEnd();
// Reset blend function
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
target->resetGLStates();
}
int main (int argc, const char * argv[])
{
// Create the main window
sf::RenderWindow window(sf::VideoMode(800, 600), "SFML window");
sf::RenderTexture lightTexture;
lightTexture.create(800, 600);
lightTexture.setSmooth(true);
lightTexture.setActive();
glEnable(GL_BLEND);
glEnable(GL_TEXTURE_2D);
window.setActive();
sf::RenderTexture layerTexture;
layerTexture.create(800, 600);
//Create background texture
sf::Texture checkerTexture;
checkerTexture.loadFromFile("checkers.png");
checkerTexture.setRepeated(true);
sf::Sprite backgroundSprite(checkerTexture);
backgroundSprite.setTextureRect(sf::IntRect(0, 0, 800, 600));
//Create circle shape
sf::CircleShape circle;
circle.setFillColor(sf::Color::Green);
circle.setRadius(40.0f);
circle.setOrigin(40, 40);
circle.setPosition(400, 0);
sf::RectangleShape strip;
strip.move(20, 0);
strip.setFillColor(sf::Color::Green);
strip.setSize(sf::Vector2f(80, 600));
float yDirection = 0.1f;
// Start the game loop
while (window.isOpen())
{
circle.move(0.0f, yDirection);
if (circle.getPosition().y >= 600.0f || circle.getPosition().y <= 0.0f) {
yDirection = -yDirection;
}
// Process events
sf::Event event;
while (window.pollEvent(event))
{
// Close window : exit
if (event.type == sf::Event::Closed)
window.close();
// Escape pressed : exit
if (event.type == sf::Event::KeyPressed && event.key.code == sf::Keyboard::Escape)
window.close();
}
// Clear screen
window.clear(sf::Color(193, 230, 237));
layerTexture.clear(sf::Color(255, 255, 255, 0));
//Render to layer texture first
layerTexture.draw(circle);
layerTexture.draw(strip);
renderLight(&layerTexture, lightTexture);
window.draw(backgroundSprite);
layerTexture.display();
sf::Sprite layers(layerTexture.getTexture());
window.draw(layers);
// Update the window
window.display();
}
return EXIT_SUCCESS;
}
Save as checkers.png
Here is what the program looks like.