main.cpp#include <vector>
#include <SFML/Graphics.hpp>
#include <GL/glew.h>
sf::RenderTexture* poRT = nullptr;
sf::RenderTexture* poRTNorm = nullptr;
class Light : public sf::Transformable
{
public:
sf::Color color;
sf::Vector3f falloff;
void draw() const
{
glUniform2f(2, getPosition().x, getPosition().y);
glUniform4f(3, color.r / 255.0f, color.g / 255.0f, color.b / 255.0f, color.a / 255.0f);
glUniform3f(4, falloff.x, falloff.y, falloff.z);
}
};
class LightEngine
{
private:
GLuint m_u32VAO, m_u32VBO, m_u32EBO;
std::vector<Light> m_aoLights;
sf::RenderTexture m_oTex;
sf::Sprite m_oSprite;
sf::Shader m_oShader;
public:
LightEngine()
{
m_oTex.create(1024, 768);
m_oTex.setActive(true);
m_oSprite.setTexture(m_oTex.getTexture());
m_oShader.loadFromFile("shaders/Vertex.vert", "shaders/Fragment.frag");
glGenVertexArrays(1, &m_u32VAO);
glBindVertexArray(m_u32VAO);
// Data for VBO
const GLfloat verts[]
{
-1.0f, 1.0f, 0.0f, 0.0f, // Top left
1.0f, 1.0f, 1.0f, 0.0f, // Top right
1.0f, -1.0f, 1.0f, 1.0f, // Bottom right
-1.0f, -1.0f, 0.0f, 1.0f, // Bottom left
};
glGenBuffers(1, &m_u32VBO);
glBindBuffer(GL_ARRAY_BUFFER, m_u32VBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(verts), verts, GL_STATIC_DRAW);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(GLfloat), nullptr);
glEnableVertexAttribArray(1);
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(GLfloat), reinterpret_cast<void*>(2 * sizeof(GLfloat)));
// Data for EBO
const GLuint elements[]
{
0, 1, 2,
2, 3, 0
};
glGenBuffers(1, &m_u32EBO);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_u32EBO);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(elements), elements, GL_STATIC_DRAW);
glBindVertexArray(0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
m_oTex.setActive(false);
// Create a test light
Light oLight;
oLight.setPosition({512, 384});
oLight.color = sf::Color::White;
oLight.falloff = {0.4f, 3.0f, 20.0f};
m_aoLights.push_back(oLight);
// Multiple lights dont work
Light oLight2;
oLight2.setPosition({100, 100});
oLight2.color = sf::Color::Green;
oLight2.falloff = {0.4f, 3.0f, 20.0f};
m_aoLights.push_back(oLight2);
Light oLight3;
oLight3.setPosition({300, 250});
oLight3.color = sf::Color::Red;
oLight3.falloff = {0.4f, 3.0f, 20.0f};
m_aoLights.push_back(oLight3);
}
void render(sf::RenderWindow& rw)
{
m_oTex.setActive(true);
m_oTex.clear();
glUseProgram(m_oShader.getNativeHandle());
glActiveTexture(GL_TEXTURE2);
glBindTexture(GL_TEXTURE_2D, poRT->getTexture().getNativeHandle());
glUniform1i(0, 2);
glActiveTexture(GL_TEXTURE3);
glBindTexture(GL_TEXTURE_2D, poRTNorm->getTexture().getNativeHandle());
glUniform1i(1, 3);
glBindVertexArray(m_u32VAO);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_COLOR, GL_ONE);
for (const auto& rkoLight : m_aoLights)
{
rkoLight.draw();
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, nullptr);
}
glDisable(GL_BLEND);
m_oTex.display();
glBindVertexArray(0);
// Cleanup. Reset Texture2 and 3 and unbind any shaders.
glActiveTexture(GL_TEXTURE2);
glBindTexture(GL_TEXTURE_2D, 0);
glActiveTexture(GL_TEXTURE3);
glBindTexture(GL_TEXTURE_2D, 0);
glUseProgram(0);
glActiveTexture(GL_TEXTURE0);
rw.setActive(true);
rw.pushGLStates();
rw.resetGLStates();
rw.draw(m_oSprite);
rw.popGLStates();
}
~LightEngine()
{
glDeleteBuffers(1, &m_u32EBO);
glDeleteBuffers(1, &m_u32VBO);
glDeleteVertexArrays(1, &m_u32VAO);
}
};
int main()
{
sf::ContextSettings oContextSettings;
oContextSettings.antialiasingLevel = 4;
oContextSettings.depthBits = 24;
oContextSettings.majorVersion = 3;
oContextSettings.minorVersion = 3;
sf::RenderWindow oApp{{1024, 768}, "OpenGL Lighting Test", sf::Style::Default, oContextSettings};
glewExperimental = 1;
glewInit();
sf::RenderTexture oRT, oRTNormals;
oRT.create(oApp.getSize().x, oApp.getSize().y);
oRTNormals.create(oApp.getSize().x, oApp.getSize().y);
poRT = &oRT;
poRTNorm = &oRTNormals;
{
{
sf::Texture oTex;
oTex.loadFromFile("bg1.png");
sf::Sprite oSpr;
oSpr.setTexture(oTex);
oSpr.setPosition({5.0f, 5.0f});
oRT.draw(oSpr);
oTex.loadFromFile("bg1_n.png");
oRTNormals.draw(oSpr);
}
{
sf::Texture oTex;
oTex.loadFromFile("bg2.png");
sf::Sprite oSpr;
oSpr.setTexture(oTex);
oSpr.setPosition({650.0f, 50.0f});
oRT.draw(oSpr);
oTex.loadFromFile("bg2_n.png");
oRTNormals.draw(oSpr);
}
{
sf::Texture oTex;
oTex.loadFromFile("bg3.png");
sf::Sprite oSpr;
oSpr.setTexture(oTex);
oSpr.setPosition({300.0f, 250.0f});
oRT.draw(oSpr);
oTex.loadFromFile("bg3_n.png");
oRTNormals.draw(oSpr);
}
}
oRT.display();
oRTNormals.display();
sf::Sprite oSprite{oRT.getTexture()};
LightEngine oEngine;
sf::Clock oClock;
bool bRunning = true;
while (bRunning)
{
sf::Event oEvent;
while (oApp.pollEvent(oEvent))
{
switch (oEvent.type)
{
case sf::Event::Closed:
{
bRunning = false;
break;
}
}
}
oApp.setActive(true);
oApp.clear();
oApp.pushGLStates();
oApp.resetGLStates();
oApp.draw(oSprite);
oApp.popGLStates();
oEngine.render(oApp);
oApp.display();
}
}
shaders/Vertex.vert#version 450 core
layout(location = 0) in vec2 position;
layout(location = 1) in vec2 uv;
layout(location = 0) out vec2 out_uv;
void main()
{
out_uv = uv;
gl_Position = vec4(position, 0.0, 1.0);
};
shaders/Fragment.frag#version 450 core
layout(location = 0) uniform sampler2D u_tex; // Diffuse map
layout(location = 1) uniform sampler2D u_texNorm; // Normal map
layout(location = 2) uniform vec2 u_lightPos;
layout(location = 3) uniform vec4 u_lightCol;
layout(location = 4) uniform vec3 u_lightFalloff;
layout(location = 0) in vec2 uv; // UV coords for this fragment
layout(location = 0) out vec4 out_color;
void main()
{
out_color = vec4(0.0, 0.5, 1.0, 1.0);
}