123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244 |
- #include "LightPointEmission.h"
- #include "LightShape.h"
- #include "LightSystem.h"
- #include <iostream>
- #include <cassert>
- #include <cmath>
- using namespace ltbl;
- void LightPointEmission::render(const sf::View& view,
- sf::RenderTexture& lightTempTexture, sf::RenderTexture& emissionTempTexture, sf::RenderTexture& antumbraTempTexture,
- const std::vector<QuadtreeOccupant*>& shapes,
- sf::Shader& unshadowShader, sf::Shader& lightOverShapeShader,
- bool normalsEnabled, sf::Shader& normalsShader)
- {
- emissionTempTexture.clear();
- emissionTempTexture.setView(view);
- emissionTempTexture.draw(_emissionSprite);
- emissionTempTexture.display();
- // Note: We don't want origin from _emissionSprite.getTransform,
- // as the center point is the origin itself.
- sf::Transform t = _emissionSprite.getTransform();
- t.translate(_emissionSprite.getOrigin());
- sf::Vector2f castCenter = t.transformPoint(_localCastCenter);
- float shadowExtension = _shadowOverExtendMultiplier * (getAABB().width + getAABB().height);
- struct OuterEdges {
- std::vector<int> _outerBoundaryIndices;
- std::vector<sf::Vector2f> _outerBoundaryVectors;
- };
- std::vector<OuterEdges> outerEdges(shapes.size());
- std::vector<int> innerBoundaryIndices;
- std::vector<sf::Vector2f> innerBoundaryVectors;
- std::vector<LightSystem::Penumbra> penumbras;
- sf::RenderStates maskRenderStates;
- maskRenderStates.blendMode = sf::BlendNone;
- sf::RenderStates antumbraRenderStates;
- antumbraRenderStates.blendMode = sf::BlendMultiply;
- //----- Emission
- lightTempTexture.clear();
- lightTempTexture.setView(view);
- if (normalsEnabled) {
- auto oglLightPosition = lightTempTexture.mapCoordsToPixel(_emissionSprite.getPosition());
- normalsShader.setParameter("lightPosition", oglLightPosition.x, static_cast<int>(lightTempTexture.getSize().y - oglLightPosition.y), 0.15f);
- const auto& lightColor = _emissionSprite.getColor();
- sf::Vector3f oglLightColor{lightColor.r / 255.f, lightColor.g / 255.f, lightColor.b / 255.f};
- normalsShader.setParameter("lightColor", oglLightColor);
- // TODO Having a better interface for emission sprite settings would make us able to precompute and stores these values
- // But all that depends on the view
- auto oglOrigin = lightTempTexture.mapCoordsToPixel({0.f, 0.f});
- auto oglLightWidthPos = lightTempTexture.mapCoordsToPixel({getAABB().width, 0.f}) - oglOrigin;
- auto oglLightHeightPos = lightTempTexture.mapCoordsToPixel({0.f, getAABB().height}) - oglOrigin;
- float oglLightWidth = std::sqrt(oglLightWidthPos.x * oglLightWidthPos.x + oglLightWidthPos.y * oglLightWidthPos.y);
- float oglLightHeight = std::sqrt(oglLightHeightPos.x * oglLightHeightPos.x + oglLightHeightPos.y * oglLightHeightPos.y);
- normalsShader.setParameter("lightSize", oglLightWidth, oglLightHeight);
- lightTempTexture.draw(_emissionSprite, &normalsShader);
- }
- else {
- lightTempTexture.draw(_emissionSprite);
- }
- //----- Shapes
- // Mask off light shape (over-masking - mask too much, reveal penumbra/antumbra afterwards)
- unsigned shapesCount = shapes.size();
- for (unsigned i = 0; i < shapesCount; ++i) {
- LightShape* pLightShape = static_cast<LightShape*>(shapes[i]);
- // Get boundaries
- innerBoundaryIndices.clear();
- innerBoundaryVectors.clear();
- penumbras.clear();
- LightSystem::getPenumbrasPoint(penumbras, innerBoundaryIndices, innerBoundaryVectors, outerEdges[i]._outerBoundaryIndices, outerEdges[i]._outerBoundaryVectors, pLightShape->_shape, castCenter, _sourceRadius);
- if (innerBoundaryIndices.size() != 2 || outerEdges[i]._outerBoundaryIndices.size() != 2)
- continue;
- // Render shape
- if (!pLightShape->_renderLightOverShape) {
- pLightShape->_shape.setFillColor(sf::Color::Black);
- lightTempTexture.draw(pLightShape->_shape);
- }
- sf::Vector2f as = pLightShape->_shape.getTransform().transformPoint(pLightShape->_shape.getPoint(outerEdges[i]._outerBoundaryIndices[0]));
- sf::Vector2f bs = pLightShape->_shape.getTransform().transformPoint(pLightShape->_shape.getPoint(outerEdges[i]._outerBoundaryIndices[1]));
- sf::Vector2f ad = outerEdges[i]._outerBoundaryVectors[0];
- sf::Vector2f bd = outerEdges[i]._outerBoundaryVectors[1];
- sf::Vector2f intersectionOuter;
- // Handle antumbras as a seperate case
- if (rayIntersect(as, ad, bs, bd, intersectionOuter)) {
- sf::Vector2f asi = pLightShape->_shape.getTransform().transformPoint(pLightShape->_shape.getPoint(innerBoundaryIndices[0]));
- sf::Vector2f bsi = pLightShape->_shape.getTransform().transformPoint(pLightShape->_shape.getPoint(innerBoundaryIndices[1]));
- sf::Vector2f adi = innerBoundaryVectors[0];
- sf::Vector2f bdi = innerBoundaryVectors[1];
- antumbraTempTexture.clear(sf::Color::White);
- antumbraTempTexture.setView(view);
- sf::Vector2f intersectionInner;
- if (rayIntersect(asi, adi, bsi, bdi, intersectionInner)) {
- sf::ConvexShape maskShape;
- maskShape.setPointCount(3);
- maskShape.setPoint(0, asi);
- maskShape.setPoint(1, bsi);
- maskShape.setPoint(2, intersectionInner);
- maskShape.setFillColor(sf::Color::Black);
- antumbraTempTexture.draw(maskShape);
- }
- else {
- sf::ConvexShape maskShape;
- maskShape.setPointCount(4);
- maskShape.setPoint(0, asi);
- maskShape.setPoint(1, bsi);
- maskShape.setPoint(2, bsi + vectorNormalize(bdi) * shadowExtension);
- maskShape.setPoint(3, asi + vectorNormalize(adi) * shadowExtension);
- maskShape.setFillColor(sf::Color::Black);
- antumbraTempTexture.draw(maskShape);
- }
- // Add light back for antumbra/penumbras
- sf::VertexArray vertexArray;
- vertexArray.setPrimitiveType(sf::PrimitiveType::Triangles);
- vertexArray.resize(3);
- sf::RenderStates penumbraRenderStates;
- penumbraRenderStates.blendMode = sf::BlendAdd;
- penumbraRenderStates.shader = &unshadowShader;
- // Unmask with penumbras
- for (unsigned j = 0; j < penumbras.size(); j++) {
- unshadowShader.setParameter("lightBrightness", penumbras[j]._lightBrightness);
- unshadowShader.setParameter("darkBrightness", penumbras[j]._darkBrightness);
- vertexArray[0].position = penumbras[j]._source;
- vertexArray[1].position = penumbras[j]._source + vectorNormalize(penumbras[j]._lightEdge) * shadowExtension;
- vertexArray[2].position = penumbras[j]._source + vectorNormalize(penumbras[j]._darkEdge) * shadowExtension;
- vertexArray[0].texCoords = sf::Vector2f(0.0f, 1.0f);
- vertexArray[1].texCoords = sf::Vector2f(1.0f, 0.0f);
- vertexArray[2].texCoords = sf::Vector2f(0.0f, 0.0f);
- antumbraTempTexture.draw(vertexArray, penumbraRenderStates);
- }
- antumbraTempTexture.display();
- // Multiply back to lightTempTexture
- sf::Sprite s;
- s.setTexture(antumbraTempTexture.getTexture());
- lightTempTexture.setView(lightTempTexture.getDefaultView());
- lightTempTexture.draw(s, antumbraRenderStates);
- lightTempTexture.setView(view);
- }
- else {
- sf::ConvexShape maskShape;
- maskShape.setPointCount(4);
- maskShape.setPoint(0, as);
- maskShape.setPoint(1, bs);
- maskShape.setPoint(2, bs + vectorNormalize(bd) * shadowExtension);
- maskShape.setPoint(3, as + vectorNormalize(ad) * shadowExtension);
- maskShape.setFillColor(sf::Color::Black);
- lightTempTexture.draw(maskShape);
- sf::VertexArray vertexArray;
- vertexArray.setPrimitiveType(sf::PrimitiveType::Triangles);
- vertexArray.resize(3);
- sf::RenderStates penumbraRenderStates;
- penumbraRenderStates.blendMode = sf::BlendMultiply;
- penumbraRenderStates.shader = &unshadowShader;
- // Unmask with penumbras
- for (unsigned j = 0; j < penumbras.size(); j++) {
- unshadowShader.setParameter("lightBrightness", penumbras[j]._lightBrightness);
- unshadowShader.setParameter("darkBrightness", penumbras[j]._darkBrightness);
- vertexArray[0].position = penumbras[j]._source;
- vertexArray[1].position = penumbras[j]._source + vectorNormalize(penumbras[j]._lightEdge) * shadowExtension;
- vertexArray[2].position = penumbras[j]._source + vectorNormalize(penumbras[j]._darkEdge) * shadowExtension;
- vertexArray[0].texCoords = sf::Vector2f(0.0f, 1.0f);
- vertexArray[1].texCoords = sf::Vector2f(1.0f, 0.0f);
- vertexArray[2].texCoords = sf::Vector2f(0.0f, 0.0f);
- lightTempTexture.draw(vertexArray, penumbraRenderStates);
- }
- }
- }
- for (unsigned i = 0; i < shapesCount; i++) {
- LightShape* pLightShape = static_cast<LightShape*>(shapes[i]);
- if (pLightShape->_renderLightOverShape) {
- pLightShape->_shape.setFillColor(sf::Color::White);
- lightTempTexture.draw(pLightShape->_shape, &lightOverShapeShader);
- }
- else {
- pLightShape->_shape.setFillColor(sf::Color::Black);
- lightTempTexture.draw(pLightShape->_shape);
- }
- }
- //----- Finish
- lightTempTexture.display();
- }
|