123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755 |
- #include "LightSystem.h"
- #include <cassert>
- #include <iostream>
- #include <cmath>
- using namespace ltbl;
- void LightSystem::getPenumbrasPoint(std::vector<Penumbra> &penumbras, std::vector<int> &innerBoundaryIndices, std::vector<sf::Vector2f> &innerBoundaryVectors, std::vector<int> &outerBoundaryIndices, std::vector<sf::Vector2f> &outerBoundaryVectors, const sf::ConvexShape &shape, const sf::Vector2f &sourceCenter, float sourceRadius) {
- const int numPoints = shape.getPointCount();
- std::vector<bool> bothEdgesBoundaryWindings;
- bothEdgesBoundaryWindings.reserve(2);
- std::vector<bool> oneEdgeBoundaryWindings;
- oneEdgeBoundaryWindings.reserve(2);
- // Calculate front and back facing sides
- std::vector<bool> facingFrontBothEdges;
- facingFrontBothEdges.reserve(numPoints);
- std::vector<bool> 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<Penumbra> &penumbras, std::vector<int> &innerBoundaryIndices, std::vector<sf::Vector2f> &innerBoundaryVectors, std::vector<int> &outerBoundaryIndices, std::vector<sf::Vector2f> &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<bool> bothEdgesBoundaryWindings;
- bothEdgesBoundaryWindings.reserve(2);
- // Calculate front and back facing sides
- std::vector<bool> facingFrontBothEdges;
- facingFrontBothEdges.reserve(numPoints);
- std::vector<bool> 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<QuadtreeOccupant*> viewPointEmissionLights;
- _lightPointEmissionQuadtree.queryRegion(viewPointEmissionLights, viewBounds);
- sf::RenderStates compoRenderStates;
- compoRenderStates.blendMode = sf::BlendAdd;
- //----- Point lights
- std::vector<QuadtreeOccupant*> lightShapes;
- sf::Sprite lightTempSprite(_lightTempTexture.getTexture());
- for (auto occupant : viewPointEmissionLights) {
- auto pPointEmissionLight = static_cast<LightPointEmission*>(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<QuadtreeOccupant*> 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<LightPointEmission> &pointEmissionLight) {
- _lightPointEmissionQuadtree.add(pointEmissionLight.get());
- _pointEmissionLights.insert(pointEmissionLight);
- }
- void LightSystem::addLight(const std::shared_ptr<LightDirectionEmission> &directionEmissionLight) {
- _directionEmissionLights.insert(directionEmissionLight);
- }
- void LightSystem::removeLight(const std::shared_ptr<LightPointEmission> &pointEmissionLight) {
- std::unordered_set<std::shared_ptr<LightPointEmission>>::iterator it = _pointEmissionLights.find(pointEmissionLight);
- if (it != _pointEmissionLights.end()) {
- (*it)->quadtreeRemove();
- _pointEmissionLights.erase(it);
- }
- }
- void LightSystem::removeLight(const std::shared_ptr<LightDirectionEmission> &directionEmissionLight) {
- std::unordered_set<std::shared_ptr<LightDirectionEmission>>::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);
- }
|