194 lines
6.0 KiB
C++
194 lines
6.0 KiB
C++
#include "Light.h"
|
|
|
|
void Light::draw(sf::RenderWindow& window)
|
|
{
|
|
if (hasFlags(Flags::visibility))
|
|
{
|
|
window.draw(m_light.data(), m_light.size(), sf::PrimitiveType::TriangleFan);
|
|
}
|
|
|
|
if (hasFlags(Flags::drawRays))
|
|
{
|
|
sf::VertexArray tempRay(sf::PrimitiveType::Lines, 2);
|
|
tempRay[start].position = m_origin;
|
|
tempRay[start].color = m_rayColor;
|
|
tempRay[end].color = m_rayColor;
|
|
|
|
for (auto& ray : m_rays)
|
|
{
|
|
tempRay[end].position = ray.position;
|
|
window.draw(tempRay);
|
|
}
|
|
}
|
|
|
|
if (hasFlags(Flags::drawEndPoints))
|
|
{
|
|
sf::CircleShape endPoint(5.f, 20u);
|
|
endPoint.setOrigin({ 5, 5 });
|
|
endPoint.setFillColor(m_endPointColor);
|
|
|
|
for (auto& ray : m_rays)
|
|
{
|
|
endPoint.setPosition(ray.position);
|
|
window.draw(endPoint);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void Light::processRays(const std::vector<sf::VertexArray>& polygons)
|
|
{
|
|
m_light[0].position = m_origin;
|
|
if (m_center and m_offset)
|
|
{
|
|
constructPartialLight(polygons);
|
|
}
|
|
else
|
|
{
|
|
constructFullLight(polygons);
|
|
}
|
|
}
|
|
|
|
|
|
void Light::constructFullLight(const std::vector<sf::VertexArray>& polygons)
|
|
{
|
|
createAndSortRays(polygons);
|
|
|
|
calculateIntersects(polygons);
|
|
|
|
for (auto& ray : m_rays)
|
|
{
|
|
m_light.emplace_back(ray);
|
|
}
|
|
|
|
m_light.emplace_back(m_rays.front());//fully connect the triangle fan
|
|
|
|
}
|
|
|
|
|
|
void Light::constructPartialLight(const std::vector<sf::VertexArray>& polygons)
|
|
{
|
|
createAndSortRays(polygons, m_center.value() - m_offset.value(), m_center.value() + m_offset.value());
|
|
|
|
calculateIntersects(polygons);
|
|
|
|
for (auto& ray : m_rays)
|
|
{
|
|
m_light.emplace_back(ray);
|
|
}
|
|
|
|
}
|
|
|
|
|
|
void Light::createAndSortRays(const std::vector<sf::VertexArray>& polygons)
|
|
{
|
|
|
|
if (not hasFlags(Flags::infiniteLength))
|
|
{
|
|
if (m_rayCount > 0)
|
|
{
|
|
float angleIncrement = 360.f / (float)m_rayCount;
|
|
for (int i = 0; i < m_rayCount; i++) m_rays.emplace_back(sf::Vertex{ constructVector( m_origin, sf::degrees(angleIncrement * i), m_rayLength ), m_lightColor });
|
|
}
|
|
}
|
|
|
|
sf::Angle angle;
|
|
|
|
for (auto& poly : polygons)
|
|
{
|
|
for (std::size_t i = 0; i < poly.getVertexCount() - 1; i++)
|
|
{
|
|
if (hasFlags(Flags::infiniteLength) ? false : distanceBetween(m_origin, poly[i].position) >= m_rayLength) continue;
|
|
|
|
angle = sf::radians(std::atan2f(poly[i].position.y - m_origin.y, poly[i].position.x - m_origin.x));
|
|
|
|
m_rays.emplace_back(sf::Vertex{ poly[i].position, m_lightColor });
|
|
m_rays.emplace_back(sf::Vertex{ constructVector( m_origin, angle + sf::radians(.00001f), m_rayLength + (5000.f * hasFlags(Flags::infiniteLength)) ), m_lightColor });
|
|
m_rays.emplace_back(sf::Vertex{ constructVector( m_origin, angle - sf::radians(.00001f), m_rayLength + (5000.f * hasFlags(Flags::infiniteLength)) ), m_lightColor });
|
|
}
|
|
}
|
|
|
|
std::sort(m_rays.begin(), m_rays.end(), [&](const auto& lhs, const auto& rhs) { return (lhs.position - m_origin).angle().wrapUnsigned().asRadians() < (rhs.position - m_origin).angle().wrapUnsigned().asRadians(); });
|
|
}
|
|
|
|
// overload for bounded light
|
|
void Light::createAndSortRays(const std::vector<sf::VertexArray>& polygons, sf::Angle lowerAngleBounds, sf::Angle upperAngleBounds)
|
|
{
|
|
|
|
sf::Vertex lowerBound{ constructVector( m_origin, lowerAngleBounds, m_rayLength + (5000.f * hasFlags(Flags::infiniteLength)) ), m_lightColor };
|
|
sf::Vertex upperBound{ constructVector( m_origin, upperAngleBounds, m_rayLength + (5000.f * hasFlags(Flags::infiniteLength)) ), m_lightColor };
|
|
auto lowerBoundVector = lowerBound.position - m_origin;
|
|
auto upperBoundVector = upperBound.position - m_origin;
|
|
|
|
if (not hasFlags(Flags::infiniteLength))
|
|
{
|
|
sf::Vertex temp;
|
|
float angleIncrement = 360.f / (float)m_rayCount;
|
|
for (int i = 0; i < m_rayCount; i++)
|
|
{
|
|
temp = sf::Vertex{ constructVector(m_origin, sf::degrees(angleIncrement * i), m_rayLength), m_lightColor };
|
|
|
|
if (withinBounds(temp.position - m_origin, lowerBoundVector, upperBoundVector)) m_rays.emplace_back(temp);
|
|
}
|
|
}
|
|
|
|
constexpr float infiniteLength = 5000.f;
|
|
sf::Angle angle;
|
|
|
|
for (auto& poly : polygons)
|
|
{
|
|
for (std::size_t i = 0; i < poly.getVertexCount() - 1; i++)
|
|
{
|
|
if (poly[i].position == m_origin) continue;// cannot pass zero vector to sf::Vector2::angleTo()
|
|
|
|
if (hasFlags(Flags::infiniteLength) ? false : distanceBetween(m_origin, poly[i].position) >= m_rayLength) continue;
|
|
|
|
if (not withinBounds(poly[i].position - m_origin, lowerBoundVector, upperBoundVector)) continue;
|
|
|
|
angle = sf::radians(std::atan2f(poly[i].position.y - m_origin.y, poly[i].position.x - m_origin.x));
|
|
|
|
m_rays.emplace_back(sf::Vertex{ poly[i].position, m_lightColor });
|
|
m_rays.emplace_back(sf::Vertex{ constructVector( m_origin, angle + sf::radians(.00001f), m_rayLength + (infiniteLength * hasFlags(Flags::infiniteLength)) ), m_lightColor });
|
|
m_rays.emplace_back(sf::Vertex{ constructVector( m_origin, angle - sf::radians(.00001f), m_rayLength + (infiniteLength * hasFlags(Flags::infiniteLength)) ), m_lightColor });
|
|
}
|
|
}
|
|
|
|
m_rays.emplace_back(lowerBound);
|
|
m_rays.emplace_back(upperBound);
|
|
|
|
std::sort(m_rays.begin(), m_rays.end(), [&](const auto& lhs, const auto& rhs) { return (lhs.position - m_origin).angleTo(upperBoundVector).wrapUnsigned().asRadians() < (rhs.position - m_origin).angleTo(upperBoundVector).wrapUnsigned().asRadians(); });
|
|
}
|
|
|
|
void Light::calculateIntersects(const std::vector<sf::VertexArray>& polygons)
|
|
{
|
|
std::optional<sf::Vector2f> currentIntersect{};
|
|
|
|
for (auto& ray : m_rays)
|
|
{
|
|
sf::Vector2f closestIntersection = ray.position;
|
|
currentIntersect.reset();
|
|
|
|
for (auto& poly : polygons)
|
|
{
|
|
for (std::size_t i = 1; i <= poly.getVertexCount() - 1; i++)
|
|
{
|
|
currentIntersect = lineIntersect({ m_origin, ray.position }, { poly[i - 1].position , poly[i].position });
|
|
|
|
if (not currentIntersect) continue;
|
|
if ((closestIntersection - m_origin).length() < (currentIntersect.value() - m_origin).length()) continue;
|
|
|
|
closestIntersection = currentIntersect.value();
|
|
}
|
|
}
|
|
|
|
ray.position = closestIntersection;
|
|
}
|
|
|
|
}
|
|
|
|
bool Light::withinBounds(sf::Vector2f point, sf::Vector2f lower, sf::Vector2f upper)
|
|
{
|
|
return point.angleTo(upper).wrapUnsigned().asRadians() < (lower).angleTo(upper).wrapUnsigned().asRadians();
|
|
}
|
|
|