#include "LightSystem.h" #include #include #include using namespace ltbl; void LightSystem::getPenumbrasPoint(std::vector &penumbras, std::vector &innerBoundaryIndices, std::vector &innerBoundaryVectors, std::vector &outerBoundaryIndices, std::vector &outerBoundaryVectors, const sf::ConvexShape &shape, const sf::Vector2f &sourceCenter, float sourceRadius) { const int numPoints = shape.getPointCount(); std::vector bothEdgesBoundaryWindings; bothEdgesBoundaryWindings.reserve(2); std::vector oneEdgeBoundaryWindings; oneEdgeBoundaryWindings.reserve(2); // Calculate front and back facing sides std::vector facingFrontBothEdges; facingFrontBothEdges.reserve(numPoints); std::vector facingFrontOneEdge; facingFrontOneEdge.reserve(numPoints); for (int i = 0; i < numPoints; i++) { sf::Vector2f point = shape.getTransform().transformPoint(shape.getPoint(i)); sf::Vector2f nextPoint; if (i < numPoints - 1) nextPoint = shape.getTransform().transformPoint(shape.getPoint(i + 1)); else nextPoint = shape.getTransform().transformPoint(shape.getPoint(0)); sf::Vector2f firstEdgeRay; sf::Vector2f secondEdgeRay; sf::Vector2f firstNextEdgeRay; sf::Vector2f secondNextEdgeRay; { sf::Vector2f sourceToPoint = point - sourceCenter; sf::Vector2f perpendicularOffset(-sourceToPoint.y, sourceToPoint.x); perpendicularOffset = vectorNormalize(perpendicularOffset); perpendicularOffset *= sourceRadius; firstEdgeRay = point - (sourceCenter - perpendicularOffset); secondEdgeRay = point - (sourceCenter + perpendicularOffset); } { sf::Vector2f sourceToPoint = nextPoint - sourceCenter; sf::Vector2f perpendicularOffset(-sourceToPoint.y, sourceToPoint.x); perpendicularOffset = vectorNormalize(perpendicularOffset); perpendicularOffset *= sourceRadius; firstNextEdgeRay = nextPoint - (sourceCenter - perpendicularOffset); secondNextEdgeRay = nextPoint - (sourceCenter + perpendicularOffset); } sf::Vector2f pointToNextPoint = nextPoint - point; sf::Vector2f normal = vectorNormalize(sf::Vector2f(-pointToNextPoint.y, pointToNextPoint.x)); // Front facing, mark it facingFrontBothEdges.push_back((vectorDot(firstEdgeRay, normal) > 0.0f && vectorDot(secondEdgeRay, normal) > 0.0f) || (vectorDot(firstNextEdgeRay, normal) > 0.0f && vectorDot(secondNextEdgeRay, normal) > 0.0f)); facingFrontOneEdge.push_back((vectorDot(firstEdgeRay, normal) > 0.0f || vectorDot(secondEdgeRay, normal) > 0.0f) || vectorDot(firstNextEdgeRay, normal) > 0.0f || vectorDot(secondNextEdgeRay, normal) > 0.0f); } // Go through front/back facing list. Where the facing direction switches, there is a boundary for (int i = 1; i < numPoints; i++) if (facingFrontBothEdges[i] != facingFrontBothEdges[i - 1]) { innerBoundaryIndices.push_back(i); bothEdgesBoundaryWindings.push_back(facingFrontBothEdges[i]); } // Check looping indices separately if (facingFrontBothEdges[0] != facingFrontBothEdges[numPoints - 1]) { innerBoundaryIndices.push_back(0); bothEdgesBoundaryWindings.push_back(facingFrontBothEdges[0]); } // Go through front/back facing list. Where the facing direction switches, there is a boundary for (int i = 1; i < numPoints; i++) if (facingFrontOneEdge[i] != facingFrontOneEdge[i - 1]) { outerBoundaryIndices.push_back(i); oneEdgeBoundaryWindings.push_back(facingFrontOneEdge[i]); } // Check looping indices separately if (facingFrontOneEdge[0] != facingFrontOneEdge[numPoints - 1]) { outerBoundaryIndices.push_back(0); oneEdgeBoundaryWindings.push_back(facingFrontOneEdge[0]); } // Compute outer boundary vectors for (unsigned bi = 0; bi < outerBoundaryIndices.size(); bi++) { int penumbraIndex = outerBoundaryIndices[bi]; bool winding = oneEdgeBoundaryWindings[bi]; sf::Vector2f point = shape.getTransform().transformPoint(shape.getPoint(penumbraIndex)); sf::Vector2f sourceToPoint = point - sourceCenter; sf::Vector2f perpendicularOffset(-sourceToPoint.y, sourceToPoint.x); perpendicularOffset = vectorNormalize(perpendicularOffset); perpendicularOffset *= sourceRadius; sf::Vector2f firstEdgeRay = point - (sourceCenter + perpendicularOffset); sf::Vector2f secondEdgeRay = point - (sourceCenter - perpendicularOffset); // Add boundary vector outerBoundaryVectors.push_back(winding ? firstEdgeRay : secondEdgeRay); } for (unsigned bi = 0; bi < innerBoundaryIndices.size(); bi++) { int penumbraIndex = innerBoundaryIndices[bi]; bool winding = bothEdgesBoundaryWindings[bi]; sf::Vector2f point = shape.getTransform().transformPoint(shape.getPoint(penumbraIndex)); sf::Vector2f sourceToPoint = point - sourceCenter; sf::Vector2f perpendicularOffset(-sourceToPoint.y, sourceToPoint.x); perpendicularOffset = vectorNormalize(perpendicularOffset); perpendicularOffset *= sourceRadius; sf::Vector2f firstEdgeRay = point - (sourceCenter + perpendicularOffset); sf::Vector2f secondEdgeRay = point - (sourceCenter - perpendicularOffset); // Add boundary vector innerBoundaryVectors.push_back(winding ? secondEdgeRay : firstEdgeRay); sf::Vector2f outerBoundaryVector = winding ? firstEdgeRay : secondEdgeRay; if (innerBoundaryIndices.size() == 1) innerBoundaryVectors.push_back(outerBoundaryVector); // Add penumbras bool hasPrevPenumbra = false; sf::Vector2f prevPenumbraLightEdgeVector; float prevBrightness = 1.0f; int counter = 0; while (penumbraIndex != -1) { sf::Vector2f nextPoint; int nextPointIndex; if (penumbraIndex < numPoints - 1) { nextPointIndex = penumbraIndex + 1; nextPoint = shape.getTransform().transformPoint(shape.getPoint(penumbraIndex + 1)); } else { nextPointIndex = 0; nextPoint = shape.getTransform().transformPoint(shape.getPoint(0)); } sf::Vector2f pointToNextPoint = nextPoint - point; sf::Vector2f prevPoint; int prevPointIndex; if (penumbraIndex > 0) { prevPointIndex = penumbraIndex - 1; prevPoint = shape.getTransform().transformPoint(shape.getPoint(penumbraIndex - 1)); } else { prevPointIndex = numPoints - 1; prevPoint = shape.getTransform().transformPoint(shape.getPoint(numPoints - 1)); } sf::Vector2f pointToPrevPoint = prevPoint - point; LightSystem::Penumbra penumbra; penumbra._source = point; if (!winding) { if (hasPrevPenumbra) penumbra._lightEdge = prevPenumbraLightEdgeVector; else penumbra._lightEdge = innerBoundaryVectors.back(); penumbra._darkEdge = outerBoundaryVector; penumbra._lightBrightness = prevBrightness; // Next point, check for intersection float intersectionAngle = std::acos(vectorDot(vectorNormalize(penumbra._lightEdge), vectorNormalize(pointToNextPoint))); float penumbraAngle = std::acos(vectorDot(vectorNormalize(penumbra._lightEdge), vectorNormalize(penumbra._darkEdge))); if (intersectionAngle < penumbraAngle) { prevBrightness = penumbra._darkBrightness = intersectionAngle / penumbraAngle; assert(prevBrightness >= 0.0f && prevBrightness <= 1.0f); penumbra._darkEdge = pointToNextPoint; penumbraIndex = nextPointIndex; if (hasPrevPenumbra) { std::swap(penumbra._darkBrightness, penumbras.back()._darkBrightness); std::swap(penumbra._lightBrightness, penumbras.back()._lightBrightness); } hasPrevPenumbra = true; prevPenumbraLightEdgeVector = penumbra._darkEdge; point = shape.getTransform().transformPoint(shape.getPoint(penumbraIndex)); sourceToPoint = point - sourceCenter; perpendicularOffset = sf::Vector2f(-sourceToPoint.y, sourceToPoint.x); perpendicularOffset = vectorNormalize(perpendicularOffset); perpendicularOffset *= sourceRadius; firstEdgeRay = point - (sourceCenter + perpendicularOffset); secondEdgeRay = point - (sourceCenter - perpendicularOffset); outerBoundaryVector = secondEdgeRay; if (!outerBoundaryVectors.empty()) { outerBoundaryVectors[0] = penumbra._darkEdge; outerBoundaryIndices[0] = penumbraIndex; } } else { penumbra._darkBrightness = 0.0f; if (hasPrevPenumbra) { std::swap(penumbra._darkBrightness, penumbras.back()._darkBrightness); std::swap(penumbra._lightBrightness, penumbras.back()._lightBrightness); } hasPrevPenumbra = false; if (!outerBoundaryVectors.empty()) { outerBoundaryVectors[0] = penumbra._darkEdge; outerBoundaryIndices[0] = penumbraIndex; } penumbraIndex = -1; } } else { if (hasPrevPenumbra) penumbra._lightEdge = prevPenumbraLightEdgeVector; else penumbra._lightEdge = innerBoundaryVectors.back(); penumbra._darkEdge = outerBoundaryVector; penumbra._lightBrightness = prevBrightness; // Next point, check for intersection float intersectionAngle = std::acos(vectorDot(vectorNormalize(penumbra._lightEdge), vectorNormalize(pointToPrevPoint))); float penumbraAngle = std::acos(vectorDot(vectorNormalize(penumbra._lightEdge), vectorNormalize(penumbra._darkEdge))); if (intersectionAngle < penumbraAngle) { prevBrightness = penumbra._darkBrightness = intersectionAngle / penumbraAngle; assert(prevBrightness >= 0.0f && prevBrightness <= 1.0f); penumbra._darkEdge = pointToPrevPoint; penumbraIndex = prevPointIndex; if (hasPrevPenumbra) { std::swap(penumbra._darkBrightness, penumbras.back()._darkBrightness); std::swap(penumbra._lightBrightness, penumbras.back()._lightBrightness); } hasPrevPenumbra = true; prevPenumbraLightEdgeVector = penumbra._darkEdge; point = shape.getTransform().transformPoint(shape.getPoint(penumbraIndex)); sourceToPoint = point - sourceCenter; perpendicularOffset = sf::Vector2f(-sourceToPoint.y, sourceToPoint.x); perpendicularOffset = vectorNormalize(perpendicularOffset); perpendicularOffset *= sourceRadius; firstEdgeRay = point - (sourceCenter + perpendicularOffset); secondEdgeRay = point - (sourceCenter - perpendicularOffset); outerBoundaryVector = firstEdgeRay; if (!outerBoundaryVectors.empty()) { outerBoundaryVectors[1] = penumbra._darkEdge; outerBoundaryIndices[1] = penumbraIndex; } } else { penumbra._darkBrightness = 0.0f; if (hasPrevPenumbra) { std::swap(penumbra._darkBrightness, penumbras.back()._darkBrightness); std::swap(penumbra._lightBrightness, penumbras.back()._lightBrightness); } hasPrevPenumbra = false; if (!outerBoundaryVectors.empty()) { outerBoundaryVectors[1] = penumbra._darkEdge; outerBoundaryIndices[1] = penumbraIndex; } penumbraIndex = -1; } } penumbras.push_back(penumbra); counter++; } } } void LightSystem::getPenumbrasDirection(std::vector &penumbras, std::vector &innerBoundaryIndices, std::vector &innerBoundaryVectors, std::vector &outerBoundaryIndices, std::vector &outerBoundaryVectors, const sf::ConvexShape &shape, const sf::Vector2f &sourceDirection, float sourceRadius, float sourceDistance) { const int numPoints = shape.getPointCount(); innerBoundaryIndices.reserve(2); innerBoundaryVectors.reserve(2); penumbras.reserve(2); std::vector bothEdgesBoundaryWindings; bothEdgesBoundaryWindings.reserve(2); // Calculate front and back facing sides std::vector facingFrontBothEdges; facingFrontBothEdges.reserve(numPoints); std::vector facingFrontOneEdge; facingFrontOneEdge.reserve(numPoints); for (int i = 0; i < numPoints; i++) { sf::Vector2f point = shape.getTransform().transformPoint(shape.getPoint(i)); sf::Vector2f nextPoint; if (i < numPoints - 1) nextPoint = shape.getTransform().transformPoint(shape.getPoint(i + 1)); else nextPoint = shape.getTransform().transformPoint(shape.getPoint(0)); sf::Vector2f firstEdgeRay; sf::Vector2f secondEdgeRay; sf::Vector2f firstNextEdgeRay; sf::Vector2f secondNextEdgeRay; sf::Vector2f perpendicularOffset(-sourceDirection.y, sourceDirection.x); perpendicularOffset = vectorNormalize(perpendicularOffset); perpendicularOffset *= sourceRadius; firstEdgeRay = point - (point - sourceDirection * sourceDistance - perpendicularOffset); secondEdgeRay = point - (point - sourceDirection * sourceDistance + perpendicularOffset); firstNextEdgeRay = nextPoint - (point - sourceDirection * sourceDistance - perpendicularOffset); secondNextEdgeRay = nextPoint - (point - sourceDirection * sourceDistance + perpendicularOffset); sf::Vector2f pointToNextPoint = nextPoint - point; sf::Vector2f normal = vectorNormalize(sf::Vector2f(-pointToNextPoint.y, pointToNextPoint.x)); // Front facing, mark it facingFrontBothEdges.push_back((vectorDot(firstEdgeRay, normal) > 0.0f && vectorDot(secondEdgeRay, normal) > 0.0f) || (vectorDot(firstNextEdgeRay, normal) > 0.0f && vectorDot(secondNextEdgeRay, normal) > 0.0f)); facingFrontOneEdge.push_back((vectorDot(firstEdgeRay, normal) > 0.0f || vectorDot(secondEdgeRay, normal) > 0.0f) || vectorDot(firstNextEdgeRay, normal) > 0.0f || vectorDot(secondNextEdgeRay, normal) > 0.0f); } // Go through front/back facing list. Where the facing direction switches, there is a boundary for (int i = 1; i < numPoints; i++) if (facingFrontBothEdges[i] != facingFrontBothEdges[i - 1]) { innerBoundaryIndices.push_back(i); bothEdgesBoundaryWindings.push_back(facingFrontBothEdges[i]); } // Check looping indices separately if (facingFrontBothEdges[0] != facingFrontBothEdges[numPoints - 1]) { innerBoundaryIndices.push_back(0); bothEdgesBoundaryWindings.push_back(facingFrontBothEdges[0]); } // Go through front/back facing list. Where the facing direction switches, there is a boundary for (int i = 1; i < numPoints; i++) if (facingFrontOneEdge[i] != facingFrontOneEdge[i - 1]) outerBoundaryIndices.push_back(i); // Check looping indices separately if (facingFrontOneEdge[0] != facingFrontOneEdge[numPoints - 1]) outerBoundaryIndices.push_back(0); for (unsigned bi = 0; bi < innerBoundaryIndices.size(); bi++) { int penumbraIndex = innerBoundaryIndices[bi]; bool winding = bothEdgesBoundaryWindings[bi]; sf::Vector2f point = shape.getTransform().transformPoint(shape.getPoint(penumbraIndex)); sf::Vector2f perpendicularOffset(-sourceDirection.y, sourceDirection.x); perpendicularOffset = vectorNormalize(perpendicularOffset); perpendicularOffset *= sourceRadius; sf::Vector2f firstEdgeRay = point - (point - sourceDirection * sourceDistance + perpendicularOffset); sf::Vector2f secondEdgeRay = point - (point - sourceDirection * sourceDistance - perpendicularOffset); // Add boundary vector innerBoundaryVectors.push_back(winding ? secondEdgeRay : firstEdgeRay); sf::Vector2f outerBoundaryVector = winding ? firstEdgeRay : secondEdgeRay; outerBoundaryVectors.push_back(outerBoundaryVector); // Add penumbras bool hasPrevPenumbra = false; sf::Vector2f prevPenumbraLightEdgeVector; float prevBrightness = 1.0f; int counter = 0; while (penumbraIndex != -1) { sf::Vector2f nextPoint; int nextPointIndex; if (penumbraIndex < numPoints - 1) { nextPointIndex = penumbraIndex + 1; nextPoint = shape.getTransform().transformPoint(shape.getPoint(penumbraIndex + 1)); } else { nextPointIndex = 0; nextPoint = shape.getTransform().transformPoint(shape.getPoint(0)); } sf::Vector2f pointToNextPoint = nextPoint - point; sf::Vector2f prevPoint; int prevPointIndex; if (penumbraIndex > 0) { prevPointIndex = penumbraIndex - 1; prevPoint = shape.getTransform().transformPoint(shape.getPoint(penumbraIndex - 1)); } else { prevPointIndex = numPoints - 1; prevPoint = shape.getTransform().transformPoint(shape.getPoint(numPoints - 1)); } sf::Vector2f pointToPrevPoint = prevPoint - point; LightSystem::Penumbra penumbra; penumbra._source = point; if (!winding) { if (hasPrevPenumbra) penumbra._lightEdge = prevPenumbraLightEdgeVector; else penumbra._lightEdge = innerBoundaryVectors.back(); penumbra._darkEdge = outerBoundaryVector; penumbra._lightBrightness = prevBrightness; // Next point, check for intersection float intersectionAngle = std::acos(vectorDot(vectorNormalize(penumbra._lightEdge), vectorNormalize(pointToNextPoint))); float penumbraAngle = std::acos(vectorDot(vectorNormalize(penumbra._lightEdge), vectorNormalize(penumbra._darkEdge))); if (intersectionAngle < penumbraAngle) { prevBrightness = penumbra._darkBrightness = intersectionAngle / penumbraAngle; assert(prevBrightness >= 0.0f && prevBrightness <= 1.0f); penumbra._darkEdge = pointToNextPoint; penumbraIndex = nextPointIndex; if (hasPrevPenumbra) { std::swap(penumbra._darkBrightness, penumbras.back()._darkBrightness); std::swap(penumbra._lightBrightness, penumbras.back()._lightBrightness); } hasPrevPenumbra = true; prevPenumbraLightEdgeVector = penumbra._darkEdge; point = shape.getTransform().transformPoint(shape.getPoint(penumbraIndex)); perpendicularOffset = sf::Vector2f(-sourceDirection.y, sourceDirection.x); perpendicularOffset = vectorNormalize(perpendicularOffset); perpendicularOffset *= sourceRadius; firstEdgeRay = point - (point - sourceDirection * sourceDistance + perpendicularOffset); secondEdgeRay = point - (point - sourceDirection * sourceDistance - perpendicularOffset); outerBoundaryVector = secondEdgeRay; } else { penumbra._darkBrightness = 0.0f; if (hasPrevPenumbra) { std::swap(penumbra._darkBrightness, penumbras.back()._darkBrightness); std::swap(penumbra._lightBrightness, penumbras.back()._lightBrightness); } hasPrevPenumbra = false; penumbraIndex = -1; } } else { if (hasPrevPenumbra) penumbra._lightEdge = prevPenumbraLightEdgeVector; else penumbra._lightEdge = innerBoundaryVectors.back(); penumbra._darkEdge = outerBoundaryVector; penumbra._lightBrightness = prevBrightness; // Next point, check for intersection float intersectionAngle = std::acos(vectorDot(vectorNormalize(penumbra._lightEdge), vectorNormalize(pointToPrevPoint))); float penumbraAngle = std::acos(vectorDot(vectorNormalize(penumbra._lightEdge), vectorNormalize(penumbra._darkEdge))); if (intersectionAngle < penumbraAngle) { prevBrightness = penumbra._darkBrightness = intersectionAngle / penumbraAngle; assert(prevBrightness >= 0.0f && prevBrightness <= 1.0f); penumbra._darkEdge = pointToPrevPoint; penumbraIndex = prevPointIndex; if (hasPrevPenumbra) { std::swap(penumbra._darkBrightness, penumbras.back()._darkBrightness); std::swap(penumbra._lightBrightness, penumbras.back()._lightBrightness); } hasPrevPenumbra = true; prevPenumbraLightEdgeVector = penumbra._darkEdge; point = shape.getTransform().transformPoint(shape.getPoint(penumbraIndex)); perpendicularOffset = sf::Vector2f(-sourceDirection.y, sourceDirection.x); perpendicularOffset = vectorNormalize(perpendicularOffset); perpendicularOffset *= sourceRadius; firstEdgeRay = point - (point - sourceDirection * sourceDistance + perpendicularOffset); secondEdgeRay = point - (point - sourceDirection * sourceDistance - perpendicularOffset); outerBoundaryVector = firstEdgeRay; } else { penumbra._darkBrightness = 0.0f; if (hasPrevPenumbra) { std::swap(penumbra._darkBrightness, penumbras.back()._darkBrightness); std::swap(penumbra._lightBrightness, penumbras.back()._lightBrightness); } hasPrevPenumbra = false; penumbraIndex = -1; } } penumbras.push_back(penumbra); counter++; } } } void LightSystem::create(const sf::FloatRect& rootRegion, const sf::Vector2u& imageSize, const sf::Texture& penumbraTexture, sf::Shader& unshadowShader, sf::Shader& lightOverShapeShader, sf::Shader& normalsShader) { _shapeQuadtree.create(rootRegion); _lightPointEmissionQuadtree.create(rootRegion); _lightTempTexture.create(imageSize.x, imageSize.y); _emissionTempTexture.create(imageSize.x, imageSize.y); _antumbraTempTexture.create(imageSize.x, imageSize.y); _compositionTexture.create(imageSize.x, imageSize.y); _normalsTexture.create(imageSize.x, imageSize.y); normalsTargetClear(); sf::Vector2f targetSizeInv = sf::Vector2f(1.0f / imageSize.x, 1.0f / imageSize.y); unshadowShader.setParameter("penumbraTexture", penumbraTexture); lightOverShapeShader.setParameter("emissionTexture", _emissionTempTexture.getTexture()); lightOverShapeShader.setParameter("targetSizeInv", targetSizeInv); normalsShader.setParameter("normalsTexture", _normalsTexture.getTexture()); normalsShader.setParameter("targetSize", imageSize.x, imageSize.y); normalsShader.setParameter("lightTexture", sf::Shader::CurrentTexture); } void LightSystem::render(const sf::View &view, sf::Shader &unshadowShader, sf::Shader &lightOverShapeShader, sf::Shader& normalsShader) { _compositionTexture.clear(_ambientColor); _compositionTexture.setView(_compositionTexture.getDefaultView()); // Get bounding rectangle of view sf::FloatRect viewBounds = sf::FloatRect(view.getCenter().x, view.getCenter().y, 0.0f, 0.0f); sf::FloatRect centeredViewBounds = rectRecenter(viewBounds, sf::Vector2f(0.0f, 0.0f)); _lightTempTexture.setView(view); viewBounds = rectExpand(viewBounds, _lightTempTexture.mapPixelToCoords(sf::Vector2i(0, 0))); viewBounds = rectExpand(viewBounds, _lightTempTexture.mapPixelToCoords(sf::Vector2i(_lightTempTexture.getSize().x, 0))); viewBounds = rectExpand(viewBounds, _lightTempTexture.mapPixelToCoords(sf::Vector2i(_lightTempTexture.getSize().x, _lightTempTexture.getSize().y))); viewBounds = rectExpand(viewBounds, _lightTempTexture.mapPixelToCoords(sf::Vector2i(0, _lightTempTexture.getSize().y))); std::vector viewPointEmissionLights; _lightPointEmissionQuadtree.queryRegion(viewPointEmissionLights, viewBounds); sf::RenderStates compoRenderStates; compoRenderStates.blendMode = sf::BlendAdd; //----- Point lights std::vector lightShapes; sf::Sprite lightTempSprite(_lightTempTexture.getTexture()); for (auto occupant : viewPointEmissionLights) { auto pPointEmissionLight = static_cast(occupant); // Query shapes this light is affected by lightShapes.clear(); _shapeQuadtree.queryRegion(lightShapes, pPointEmissionLight->getAABB()); pPointEmissionLight->render(view, _lightTempTexture, _emissionTempTexture, _antumbraTempTexture, lightShapes, unshadowShader, lightOverShapeShader, _normalsEnabled, normalsShader); _compositionTexture.draw(lightTempSprite, compoRenderStates); } //----- Direction lights for (const auto& directionEmissionLight : _directionEmissionLights) { LightDirectionEmission* pDirectionEmissionLight = directionEmissionLight.get(); float maxDim = std::max(centeredViewBounds.width, centeredViewBounds.height); sf::FloatRect extendedViewBounds = rectFromBounds(sf::Vector2f(-maxDim, -maxDim) * _directionEmissionRadiusMultiplier, sf::Vector2f(maxDim, maxDim) * _directionEmissionRadiusMultiplier + sf::Vector2f(_directionEmissionRange, 0.0f)); float shadowExtension = vectorMagnitude(rectLowerBound(centeredViewBounds)) * _directionEmissionRadiusMultiplier * 2.0f; sf::ConvexShape directionShape = shapeFromRect(extendedViewBounds); directionShape.setPosition(view.getCenter()); sf::Vector2f normalizedCastDirection = vectorNormalize(pDirectionEmissionLight->_castDirection); directionShape.setRotation(_radToDeg * std::atan2(normalizedCastDirection.y, normalizedCastDirection.x)); std::vector viewLightShapes; _shapeQuadtree.queryShape(viewLightShapes, directionShape); pDirectionEmissionLight->render(view, _lightTempTexture, _antumbraTempTexture, viewLightShapes, unshadowShader, shadowExtension); sf::Sprite sprite; sprite.setTexture(_lightTempTexture.getTexture()); _compositionTexture.draw(sprite, compoRenderStates); // TODO Normals } _compositionTexture.display(); } LightShape* LightSystem::allocateShape() { return _lightShapesPool.newElement(); } void LightSystem::deallocateShape(LightShape* pLightShape) { _lightShapesPool.deleteElement(pLightShape); } void LightSystem::addShape(LightShape* pLightShape) { _shapeQuadtree.add(pLightShape); } void LightSystem::removeShape(LightShape* pLightShape) { pLightShape->quadtreeRemove(); } void LightSystem::addLight(const std::shared_ptr &pointEmissionLight) { _lightPointEmissionQuadtree.add(pointEmissionLight.get()); _pointEmissionLights.insert(pointEmissionLight); } void LightSystem::addLight(const std::shared_ptr &directionEmissionLight) { _directionEmissionLights.insert(directionEmissionLight); } void LightSystem::removeLight(const std::shared_ptr &pointEmissionLight) { std::unordered_set>::iterator it = _pointEmissionLights.find(pointEmissionLight); if (it != _pointEmissionLights.end()) { (*it)->quadtreeRemove(); _pointEmissionLights.erase(it); } } void LightSystem::removeLight(const std::shared_ptr &directionEmissionLight) { std::unordered_set>::iterator it = _directionEmissionLights.find(directionEmissionLight); if (it != _directionEmissionLights.end()) _directionEmissionLights.erase(it); } //----- Normals -----// void LightSystem::normalsEnabled(bool enabled) { _normalsEnabled = enabled; } void LightSystem::normalsTargetSetView(sf::View view) { _normalsTexture.setView(view); } void LightSystem::normalsTargetClear() { _normalsTexture.clear(sf::Color{127u, 127u, 255u}); } void LightSystem::normalsTargetDisplay() { _normalsTexture.display(); } void LightSystem::normalsTargetDraw(const sf::Drawable& drawable, sf::RenderStates states) { _normalsTexture.draw(drawable, states); }