Major code rewrite.
-class Light added to handle the construction of the triangle fan -light can now be bounded between two bounderies -differnt sections of main have been placed into different functions for readability -imgui variables were made inline and moved to Utility.hpp for convenience -the claculation of intersections for rays hav been moved to Ray::calculateIntersect -variables containing std::vector<Ray>, class Light, and std::vector<sf::VertexArray> were moved outsid of main() for convenience
This commit is contained in:
parent
637dc7e821
commit
a3672012f6
|
|
@ -0,0 +1,94 @@
|
||||||
|
#include "Light.h"
|
||||||
|
|
||||||
|
void Light::draw(sf::RenderWindow& window)
|
||||||
|
{
|
||||||
|
if (not m_visible) return;
|
||||||
|
|
||||||
|
changeColor(lightColor.asSfColor());
|
||||||
|
window.draw(m_light.data(), m_light.size(), sf::PrimitiveType::TriangleFan);
|
||||||
|
if (not drawEndPoints) return;
|
||||||
|
for (auto& point : m_light)
|
||||||
|
{
|
||||||
|
point.color = sf::Color::Black;
|
||||||
|
sf::CircleShape endPoint(5.f, 20u);
|
||||||
|
endPoint.setOrigin({ 5, 5 });
|
||||||
|
endPoint.setFillColor(rayColor.asSfColor());
|
||||||
|
endPoint.setPosition(point.position);
|
||||||
|
window.draw(endPoint);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Light::addRay(Ray ray)
|
||||||
|
{
|
||||||
|
m_rays.emplace_back(ray);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Light::changeColor(sf::Color color)
|
||||||
|
{
|
||||||
|
for (auto& points : m_light)
|
||||||
|
points.color = color;
|
||||||
|
|
||||||
|
for (auto& ray : m_rays)
|
||||||
|
ray.changeColor(color);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Light::processRays(const std::vector<sf::VertexArray>& polygons)
|
||||||
|
{
|
||||||
|
if (m_center and m_offset)
|
||||||
|
{
|
||||||
|
constructPartialLight(polygons);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
constructFullLight();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void Light::constructFullLight()
|
||||||
|
{
|
||||||
|
std::sort(m_rays.begin(), m_rays.end(), [](const auto& lhs, const auto& rhs) { return lhs.angle().wrapUnsigned().asRadians() < rhs.angle().wrapUnsigned().asRadians(); });
|
||||||
|
|
||||||
|
for (auto& ray : m_rays)
|
||||||
|
{
|
||||||
|
m_light.emplace_back(ray.points()[end]);
|
||||||
|
}
|
||||||
|
|
||||||
|
m_light.emplace_back(m_rays.front().points()[end]);//fully connect the triangle fan
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void Light::constructPartialLight(const std::vector<sf::VertexArray>& polygons)
|
||||||
|
{
|
||||||
|
auto upperAngleBound = m_center.value() + m_offset.value();
|
||||||
|
auto lowerAngleBound = m_center.value() - m_offset.value();
|
||||||
|
Ray upperBound(m_light[0].position, rayLength, upperAngleBound, lightColor.asSfColor());
|
||||||
|
Ray lowerBound(m_light[0].position, rayLength, lowerAngleBound, lightColor.asSfColor());
|
||||||
|
|
||||||
|
m_rays.emplace_back(upperBound);
|
||||||
|
m_rays.emplace_back(lowerBound);
|
||||||
|
for (auto& ray : m_rays)
|
||||||
|
{
|
||||||
|
ray.calculateIntersect(polygons);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((m_center.value().wrapUnsigned().asDegrees() - m_offset.value().wrapUnsigned().asDegrees() < 0.f) or (m_center.value().wrapUnsigned().asDegrees() + m_offset.value().wrapUnsigned().asDegrees() > 360.f))
|
||||||
|
{
|
||||||
|
std::sort(m_rays.begin(), m_rays.end(), [](const auto& lhs, const auto& rhs) { return lhs.angle().wrapSigned().asRadians() < rhs.angle().wrapSigned().asRadians(); });
|
||||||
|
for (auto& ray : m_rays)
|
||||||
|
if (ray.angle().wrapSigned() >= lowerAngleBound.wrapSigned() and ray.angle().wrapSigned() <= upperAngleBound.wrapSigned())
|
||||||
|
{
|
||||||
|
m_light.emplace_back(ray.points()[end]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
std::sort(m_rays.begin(), m_rays.end(), [](const auto& lhs, const auto& rhs) { return lhs.angle().wrapUnsigned().asRadians() < rhs.angle().wrapUnsigned().asRadians(); });
|
||||||
|
for (auto& ray : m_rays)
|
||||||
|
if (ray.angle().wrapUnsigned() >= lowerAngleBound.wrapUnsigned() and ray.angle().wrapUnsigned() <= upperAngleBound.wrapUnsigned())
|
||||||
|
{
|
||||||
|
m_light.emplace_back(ray.points()[end]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,77 @@
|
||||||
|
#pragma once
|
||||||
|
#include <cmath>
|
||||||
|
#include <iostream>
|
||||||
|
#include <vector>
|
||||||
|
#include <algorithm>
|
||||||
|
#include <cstddef>
|
||||||
|
|
||||||
|
#include <SFML/Graphics.hpp>
|
||||||
|
#include <imgui-SFML.h>
|
||||||
|
#include <imgui.h>
|
||||||
|
|
||||||
|
#include "Utility.hpp"
|
||||||
|
#include "Ray.h"
|
||||||
|
|
||||||
|
class Light
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
Light(bool visible = true)
|
||||||
|
: m_visible(visible)
|
||||||
|
{
|
||||||
|
m_light.push_back(sf::Vertex());
|
||||||
|
}
|
||||||
|
|
||||||
|
Light(sf::Angle center, sf::Angle offset, bool visible = true)
|
||||||
|
: m_center(center)
|
||||||
|
, m_offset(offset)
|
||||||
|
, m_visible(visible)
|
||||||
|
{
|
||||||
|
m_light.push_back(sf::Vertex{});
|
||||||
|
}
|
||||||
|
|
||||||
|
void addAngleBounds(sf::Angle center, sf::Angle offset)
|
||||||
|
{
|
||||||
|
m_center = center;
|
||||||
|
m_offset = offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
void removeAngleBounds()
|
||||||
|
{
|
||||||
|
m_center.reset();
|
||||||
|
m_offset.reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
void setVisibility(bool input) { m_visible = input; }
|
||||||
|
bool visible() const { return m_visible; }
|
||||||
|
|
||||||
|
void setCenterAngle(sf::Angle center) { m_center = center; }
|
||||||
|
std::optional<sf::Angle> getCenterAngle() const { return m_center; }
|
||||||
|
|
||||||
|
void setOffsetAngle(sf::Angle offset) { m_offset = offset; }
|
||||||
|
std::optional<sf::Angle> getOffsetAngle() const { return m_offset; }
|
||||||
|
|
||||||
|
sf::Vector2f getOrigin() const { return m_light[0].position; }
|
||||||
|
void setOrigin(sf::Vector2f center) { m_light[0].position = center; }
|
||||||
|
|
||||||
|
void draw(sf::RenderWindow& window);
|
||||||
|
|
||||||
|
void addRay(Ray ray);
|
||||||
|
|
||||||
|
void clearRays() { m_rays.clear(); m_light.clear(); m_light.push_back(sf::Vertex{});}
|
||||||
|
|
||||||
|
void changeColor(sf::Color color);
|
||||||
|
|
||||||
|
void processRays(const std::vector<sf::VertexArray>& polygons);
|
||||||
|
private:
|
||||||
|
std::vector<sf::Vertex> m_light{};
|
||||||
|
RayVector m_rays{};
|
||||||
|
std::optional<sf::Angle> m_center{};
|
||||||
|
std::optional<sf::Angle> m_offset{};
|
||||||
|
|
||||||
|
bool m_visible{};
|
||||||
|
|
||||||
|
void constructFullLight();
|
||||||
|
void constructPartialLight(const std::vector<sf::VertexArray>& polygons);
|
||||||
|
};
|
||||||
|
|
||||||
20
Ray.cpp
20
Ray.cpp
|
|
@ -167,3 +167,23 @@
|
||||||
m_points[start].color = color;
|
m_points[start].color = color;
|
||||||
m_points[end].color = color;
|
m_points[end].color = color;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Ray::calculateIntersect(const std::vector<sf::VertexArray>& polygons)
|
||||||
|
{
|
||||||
|
sf::Vector2f closestIntersection = m_points[end].position;
|
||||||
|
std::optional<sf::Vector2f> currentIntersect{};
|
||||||
|
for (auto& poly : polygons)
|
||||||
|
{
|
||||||
|
for (int i = 1; i <= poly.getVertexCount() - 1; i++) {
|
||||||
|
currentIntersect = lineIntersect({ m_points[start].position, m_points[end].position }, { poly[i - 1].position , poly[i].position });
|
||||||
|
if (currentIntersect)
|
||||||
|
{
|
||||||
|
if ((closestIntersection - m_points[start].position).length() > (currentIntersect.value() - m_points[start].position).length())
|
||||||
|
{
|
||||||
|
closestIntersection = currentIntersect.value();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
changeEnd(closestIntersection);
|
||||||
|
}
|
||||||
|
|
|
||||||
4
Ray.h
4
Ray.h
|
|
@ -33,7 +33,7 @@ public:
|
||||||
void change(const Ray& ray, bool copyColor = false);
|
void change(const Ray& ray, bool copyColor = false);
|
||||||
void change(sf::Vector2f startPoint, sf::Vector2f endPoint);
|
void change(sf::Vector2f startPoint, sf::Vector2f endPoint);
|
||||||
void change(sf::Vector2f startPoint, sf::Vector2f endPoint, sf::Color color);
|
void change(sf::Vector2f startPoint, sf::Vector2f endPoint, sf::Color color);
|
||||||
|
|
||||||
void changeStart(sf::Vector2f startPoint, sf::Color color);
|
void changeStart(sf::Vector2f startPoint, sf::Color color);
|
||||||
void changeStart(sf::Vector2f startPoint);
|
void changeStart(sf::Vector2f startPoint);
|
||||||
void changeStart(const Ray& ray, bool copyColor = false);
|
void changeStart(const Ray& ray, bool copyColor = false);
|
||||||
|
|
@ -44,6 +44,8 @@ public:
|
||||||
|
|
||||||
void changeColor(sf::Color color);
|
void changeColor(sf::Color color);
|
||||||
|
|
||||||
|
void calculateIntersect(const std::vector<sf::VertexArray>& polygons);
|
||||||
|
|
||||||
bool operator== (const Ray& rhs)
|
bool operator== (const Ray& rhs)
|
||||||
{
|
{
|
||||||
return m_points[start].position == rhs.points()[start].position and m_points[end].position == rhs.points()[end].position;
|
return m_points[start].position == rhs.points()[start].position and m_points[end].position == rhs.points()[end].position;
|
||||||
|
|
|
||||||
19
Utility.hpp
19
Utility.hpp
|
|
@ -9,6 +9,8 @@
|
||||||
#include "Random.h"
|
#include "Random.h"
|
||||||
#include "Ray.h"
|
#include "Ray.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
template<typename T, typename U, typename V>
|
template<typename T, typename U, typename V>
|
||||||
inline T getRandomNumber(U min, V max)
|
inline T getRandomNumber(U min, V max)
|
||||||
{
|
{
|
||||||
|
|
@ -131,3 +133,20 @@ inline float distanceBetween(sf::Vector2f startPoint, sf::Vector2f endPoint)
|
||||||
{
|
{
|
||||||
return sqrtf(powf(endPoint.x - startPoint.x, 2) + powf(endPoint.y - startPoint.y, 2));
|
return sqrtf(powf(endPoint.x - startPoint.x, 2) + powf(endPoint.y - startPoint.y, 2));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//imGui Variables
|
||||||
|
inline sf::Vector2f mousePos{};
|
||||||
|
inline float polySize[2] = { 100.f, 100.f };
|
||||||
|
inline int numRays{ 500 };
|
||||||
|
inline int vertexBounds[2] = { 3u, 10u };
|
||||||
|
inline int averageSize{ 100u };
|
||||||
|
inline float rayLength{ 500.f };
|
||||||
|
inline imguiColor rayColor = constructImguiColor(sf::Color::Red);
|
||||||
|
inline imguiColor lightColor = constructImguiColor(sf::Color::Yellow);
|
||||||
|
inline bool drawRays{ false };
|
||||||
|
inline bool drawLight{ true };
|
||||||
|
inline bool drawEndPoints{ false };
|
||||||
|
inline bool boundedLight{ false };
|
||||||
|
inline int lightCenterAngle{0};
|
||||||
|
inline int lightOffsetAngle{45};
|
||||||
|
|
@ -3,6 +3,6 @@ Pos=60,60
|
||||||
Size=400,400
|
Size=400,400
|
||||||
|
|
||||||
[Window][Config]
|
[Window][Config]
|
||||||
Pos=7,7
|
Pos=44,11
|
||||||
Size=710,322
|
Size=708,467
|
||||||
|
|
||||||
|
|
|
||||||
434
main.cpp
434
main.cpp
|
|
@ -10,231 +10,261 @@
|
||||||
|
|
||||||
#include "Utility.hpp"
|
#include "Utility.hpp"
|
||||||
#include "Ray.h"
|
#include "Ray.h"
|
||||||
|
#include "Light.h"
|
||||||
|
|
||||||
|
|
||||||
|
auto window = sf::RenderWindow(sf::VideoMode({ 1920u, 1080u }), "Ray Casting Test");
|
||||||
|
|
||||||
|
Light light;
|
||||||
|
RayVector rays;
|
||||||
|
std::vector<sf::VertexArray> polygons;
|
||||||
|
|
||||||
|
void GUI();
|
||||||
|
void userInput(std::vector<sf::VertexArray>& polygons);
|
||||||
|
void processRays();
|
||||||
|
void render();
|
||||||
|
|
||||||
int main()
|
int main()
|
||||||
{
|
{
|
||||||
sf::Vector2f center{ 1920.f / 2.f, 1080.f / 2.f };
|
sf::Vector2f center{ 1920.f / 2.f, 1080.f / 2.f };
|
||||||
|
|
||||||
//sfml setup
|
//sfml setup
|
||||||
auto window = sf::RenderWindow(sf::VideoMode({ 1920u, 1080u }), "Ray Casting Test");
|
sf::Clock clock;
|
||||||
|
|
||||||
window.setFramerateLimit(144);
|
window.setFramerateLimit(144);
|
||||||
if (!ImGui::SFML::Init(window))
|
if (!ImGui::SFML::Init(window))
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
sf::Clock clock;
|
mousePos = center;
|
||||||
sf::Vector2f mousePos = center;
|
|
||||||
|
|
||||||
//imGui Variables
|
polygons.emplace_back(constructRectangle(center, center));
|
||||||
float polySize[2] = { 100.f, 100.f };
|
|
||||||
int numRays{ 500 };
|
|
||||||
int vertexBounds[2] = { 3u, 10u };
|
|
||||||
int averageSize{ 100u };
|
|
||||||
float rayLength{ 500.f };
|
|
||||||
imguiColor rayColor = constructImguiColor(sf::Color::Red);
|
|
||||||
imguiColor lightColor = constructImguiColor(sf::Color::Red);
|
|
||||||
bool drawRays{ false };
|
|
||||||
bool drawLight{ true };
|
|
||||||
|
|
||||||
|
|
||||||
//initalize vectors
|
|
||||||
RayVector rays;
|
|
||||||
|
|
||||||
std::vector<sf::VertexArray> polygons;
|
|
||||||
polygons.push_back(constructRectangle(center, center));
|
|
||||||
|
|
||||||
//main game loop
|
//main game loop
|
||||||
while (window.isOpen())
|
while (window.isOpen())
|
||||||
{
|
{
|
||||||
rays.clear();
|
|
||||||
//handle input
|
|
||||||
while (const std::optional event = window.pollEvent())
|
|
||||||
{
|
|
||||||
ImGui::SFML::ProcessEvent(window, *event);
|
|
||||||
|
|
||||||
if (event->is<sf::Event::Closed>())
|
|
||||||
{
|
|
||||||
window.close();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (const auto* buttonPressed = event->getIf<sf::Event::KeyPressed>())
|
|
||||||
{
|
|
||||||
switch (buttonPressed->scancode)
|
|
||||||
{
|
|
||||||
case sf::Keyboard::Scancode::C:
|
|
||||||
polygons.clear();
|
|
||||||
break;
|
|
||||||
|
|
||||||
case sf::Keyboard::Scancode::R:
|
|
||||||
polygons.push_back(constructRandomPolygon(mousePos, vertexBounds[0] + 1, vertexBounds[1] + 1, averageSize));
|
|
||||||
break;
|
|
||||||
|
|
||||||
case sf::Keyboard::Scancode::Escape:
|
|
||||||
window.close();
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (const auto* mousePressed = event->getIf<sf::Event::MouseButtonPressed>())
|
|
||||||
{
|
|
||||||
switch (mousePressed->button)
|
|
||||||
{
|
|
||||||
case sf::Mouse::Button::Right:
|
|
||||||
polygons.push_back(constructRectangle((sf::Vector2f)mousePressed->position, { polySize[0], polySize[1] }, sf::Color::Black));
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (const auto* mouseMoved = event->getIf<sf::Event::MouseMoved>())
|
|
||||||
{
|
|
||||||
mousePos = (sf::Vector2f)mouseMoved->position;
|
|
||||||
for (auto& ray : rays) ray.changeStart(mousePos);
|
|
||||||
}
|
|
||||||
}// end user input loop
|
|
||||||
|
|
||||||
if (numRays > 0)
|
|
||||||
{
|
|
||||||
float i = 0.f, angleIncrement = 360.f / (float)numRays;
|
|
||||||
for (int i = 0; i < numRays; i++) rays.push_back(Ray(mousePos, rayLength, sf::degrees(angleIncrement * i), rayColor.asSfColor()));
|
|
||||||
}
|
|
||||||
|
|
||||||
for (auto& poly : polygons)
|
|
||||||
{
|
|
||||||
for (std::size_t i = 0; i < poly.getVertexCount() - 1; i++)
|
|
||||||
{
|
|
||||||
if (distanceBetween(mousePos, poly[i].position) <= rayLength)
|
|
||||||
{
|
|
||||||
sf::Angle angle = sf::radians(std::atan2f(poly[i].position.y - mousePos.y, poly[i].position.x - mousePos.x));
|
|
||||||
rays.push_back(Ray(mousePos, poly[i].position, rayColor.asSfColor()));
|
|
||||||
rays.push_back(Ray(mousePos, rayLength, angle + sf::radians(.00001f), rayColor.asSfColor()));
|
|
||||||
rays.push_back(Ray(mousePos, rayLength, angle - sf::radians(.00001f), rayColor.asSfColor()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (auto& ray : rays)
|
|
||||||
{
|
|
||||||
auto& rayPoints = ray.points();
|
|
||||||
sf::Vector2f closestIntersection = rayPoints[end].position;
|
|
||||||
std::optional<sf::Vector2f> currentIntersect{};
|
|
||||||
for (auto& poly : polygons)
|
|
||||||
{
|
|
||||||
for (int i = 1; i <= poly.getVertexCount() - 1; i++) {
|
|
||||||
currentIntersect = lineIntersect({ rayPoints[start].position, rayPoints[end].position }, { poly[i - 1].position , poly[i].position });
|
|
||||||
if (currentIntersect)
|
|
||||||
{
|
|
||||||
if ((closestIntersection - rayPoints[start].position).length() > (currentIntersect.value() - rayPoints[start].position).length())
|
|
||||||
{
|
|
||||||
closestIntersection = currentIntersect.value();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ray.changeEnd(closestIntersection);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::sort(rays.begin(), rays.end(), [](const auto& lhs, const auto& rhs) { return lhs.angle().wrapUnsigned().asRadians() < rhs.angle().wrapUnsigned().asRadians(); });
|
|
||||||
|
|
||||||
sf::VertexArray light(sf::PrimitiveType::TriangleFan, 1);
|
|
||||||
if (not rays.empty())
|
|
||||||
{
|
|
||||||
light[0].position = mousePos;
|
|
||||||
light[0].color = lightColor.asSfColor();
|
|
||||||
for (auto& ray : rays)
|
|
||||||
{
|
|
||||||
light.append(ray.points()[end]);
|
|
||||||
}
|
|
||||||
light.append(rays.front().points()[end]);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int i = 0; i < light.getVertexCount(); i++)
|
|
||||||
light[i].color = lightColor.asSfColor();
|
|
||||||
|
|
||||||
|
|
||||||
ImGui::SFML::Update(window, clock.restart());
|
ImGui::SFML::Update(window, clock.restart());
|
||||||
|
|
||||||
ImGui::Begin("Config");
|
rays.clear();
|
||||||
ImGui::Text("Controls:");
|
light.clearRays();
|
||||||
ImGui::Indent();
|
|
||||||
ImGui::Text("Right Click: place rectangle at mouse position");
|
|
||||||
ImGui::Text("R: place a randomly sized polygon at mouse position");
|
|
||||||
ImGui::Text("C: clear all polygons");
|
|
||||||
ImGui::Unindent();
|
|
||||||
ImGui::Checkbox("Render rays", &drawRays);
|
|
||||||
ImGui::SameLine();
|
|
||||||
ImGui::Checkbox("Render light", &drawLight);
|
|
||||||
if (ImGui::SliderInt("number of rays", &numRays, 5, 500))
|
|
||||||
{
|
|
||||||
rays.clear();
|
|
||||||
|
|
||||||
{
|
userInput(polygons);
|
||||||
float i = 0.f, angleIncrement = 360.f / (float)numRays;
|
|
||||||
for (int i = 0; i < numRays; i++) rays.push_back(Ray(mousePos, rayLength, sf::degrees(angleIncrement * i), rayColor.asSfColor()));
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
processRays();
|
||||||
ImGui::InputFloat("Ray Length", &rayLength);
|
|
||||||
if (ImGui::ColorEdit3("Ray color", &rayColor.r))
|
|
||||||
{
|
|
||||||
for (auto& ray : rays) ray.changeColor(rayColor.asSfColor());
|
|
||||||
}
|
|
||||||
if (ImGui::ColorEdit3("Light color", &lightColor.r))
|
|
||||||
{
|
|
||||||
for (int i = 0; i < light.getVertexCount(); i++)
|
|
||||||
light[i].color = lightColor.asSfColor();
|
|
||||||
}
|
|
||||||
ImGui::InputFloat2("rectangle Size (X,Y)", polySize, "%.1f");
|
|
||||||
ImGui::Text("Random polygon config: ");
|
|
||||||
if (ImGui::SliderInt2("vertex count lower/upper bounds", vertexBounds, 3, 20))
|
|
||||||
{
|
|
||||||
if (vertexBounds[0] > vertexBounds[1])
|
|
||||||
vertexBounds[0] = vertexBounds[1];
|
|
||||||
|
|
||||||
if (vertexBounds[1] < vertexBounds[0])
|
light.setOrigin(mousePos);
|
||||||
vertexBounds[0] = vertexBounds[1];
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ImGui::InputInt("Average size", &averageSize))
|
for (auto& ray : rays) light.addRay(ray);
|
||||||
{
|
|
||||||
if (averageSize < 20)
|
|
||||||
{
|
|
||||||
averageSize = 20;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ImGui::End();
|
GUI();
|
||||||
|
|
||||||
window.clear(sf::Color::White);
|
render();
|
||||||
|
|
||||||
//render entities
|
|
||||||
for (auto& poly : polygons) window.draw(poly);
|
|
||||||
|
|
||||||
if (drawRays)
|
|
||||||
{
|
|
||||||
for (auto& ray : rays)
|
|
||||||
{
|
|
||||||
auto& rayPoints = ray.points();
|
|
||||||
sf::CircleShape endPoint(5.f, 20u);
|
|
||||||
endPoint.setOrigin({ 5, 5 });
|
|
||||||
endPoint.setFillColor(rayColor.asSfColor());
|
|
||||||
endPoint.setPosition(rayPoints[end].position);
|
|
||||||
window.draw(rayPoints);
|
|
||||||
window.draw(endPoint);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (drawLight) window.draw(light);
|
|
||||||
|
|
||||||
ImGui::SFML::Render(window);
|
|
||||||
|
|
||||||
window.display();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ImGui::SFML::Shutdown();
|
ImGui::SFML::Shutdown();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void GUI()
|
||||||
|
{
|
||||||
|
ImGui::Begin("Config");
|
||||||
|
ImGui::Text("Controls:");
|
||||||
|
ImGui::Indent();
|
||||||
|
ImGui::Text("Right Click: place rectangle at mouse position");
|
||||||
|
ImGui::Text("R: place a randomly sized polygon at mouse position");
|
||||||
|
ImGui::Text("C: clear all polygons");
|
||||||
|
ImGui::Text("Scroll wheel: increase/decrease light direction (if light is bounded)");
|
||||||
|
ImGui::Unindent();
|
||||||
|
ImGui::Checkbox("Render rays", &drawRays);
|
||||||
|
ImGui::SameLine();
|
||||||
|
if (ImGui::Checkbox("Render light", &drawLight))
|
||||||
|
{
|
||||||
|
light.setVisibility(drawLight);
|
||||||
|
}
|
||||||
|
if (ImGui::SliderInt("number of rays", &numRays, 5, 500))
|
||||||
|
{
|
||||||
|
rays.clear();
|
||||||
|
|
||||||
|
{
|
||||||
|
float i = 0.f, angleIncrement = 360.f / (float)numRays;
|
||||||
|
for (int i = 0; i < numRays; i++) rays.emplace_back(mousePos, rayLength, sf::degrees(angleIncrement * i), rayColor.asSfColor());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
ImGui::InputFloat("Ray Length", &rayLength);
|
||||||
|
if (ImGui::ColorEdit3("Ray color", &rayColor.r))
|
||||||
|
{
|
||||||
|
for (auto& ray : rays) ray.changeColor(rayColor.asSfColor());
|
||||||
|
}
|
||||||
|
ImGui::ColorEdit3("Light color", &lightColor.r);
|
||||||
|
if(ImGui::Checkbox("Light is bounded", &boundedLight))
|
||||||
|
{
|
||||||
|
if (boundedLight)
|
||||||
|
{
|
||||||
|
light.addAngleBounds(sf::degrees((float)lightCenterAngle), sf::degrees((float)lightOffsetAngle));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
light.removeAngleBounds();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (boundedLight)
|
||||||
|
{
|
||||||
|
ImGui::Checkbox("Draw end points", &drawEndPoints);
|
||||||
|
ImGui::SliderInt("Light direction", &lightCenterAngle, 0, 359);
|
||||||
|
light.setCenterAngle(sf::degrees((float)lightCenterAngle));
|
||||||
|
|
||||||
|
if (ImGui::InputInt("Offset size", &lightOffsetAngle))
|
||||||
|
{
|
||||||
|
if (lightOffsetAngle > 89)
|
||||||
|
{
|
||||||
|
lightOffsetAngle = 89;
|
||||||
|
}
|
||||||
|
if (lightOffsetAngle < 0)
|
||||||
|
{
|
||||||
|
lightOffsetAngle = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
light.setOffsetAngle(sf::degrees((float)lightOffsetAngle));
|
||||||
|
}
|
||||||
|
ImGui::InputFloat2("rectangle Size (X,Y)", polySize, "%.1f");
|
||||||
|
ImGui::Text("Random polygon config: ");
|
||||||
|
if (ImGui::SliderInt2("vertex count lower/upper bounds", vertexBounds, 3, 20))
|
||||||
|
{
|
||||||
|
if (vertexBounds[0] > vertexBounds[1])
|
||||||
|
vertexBounds[0] = vertexBounds[1];
|
||||||
|
|
||||||
|
if (vertexBounds[1] < vertexBounds[0])
|
||||||
|
vertexBounds[0] = vertexBounds[1];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ImGui::InputInt("Average size", &averageSize))
|
||||||
|
{
|
||||||
|
if (averageSize < 20)
|
||||||
|
{
|
||||||
|
averageSize = 20;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui::End();
|
||||||
|
}
|
||||||
|
|
||||||
|
void userInput(std::vector<sf::VertexArray>& polygons)
|
||||||
|
{
|
||||||
|
while (const std::optional event = window.pollEvent())
|
||||||
|
{
|
||||||
|
ImGui::SFML::ProcessEvent(window, *event);
|
||||||
|
|
||||||
|
if (event->is<sf::Event::Closed>())
|
||||||
|
{
|
||||||
|
window.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (const auto* buttonPressed = event->getIf<sf::Event::KeyPressed>())
|
||||||
|
{
|
||||||
|
switch (buttonPressed->scancode)
|
||||||
|
{
|
||||||
|
case sf::Keyboard::Scancode::C:
|
||||||
|
polygons.clear();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case sf::Keyboard::Scancode::R:
|
||||||
|
polygons.emplace_back(constructRandomPolygon(mousePos, vertexBounds[0] + 1, vertexBounds[1] + 1, averageSize));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case sf::Keyboard::Scancode::Escape:
|
||||||
|
window.close();
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (const auto* mousePressed = event->getIf<sf::Event::MouseButtonPressed>())
|
||||||
|
{
|
||||||
|
switch (mousePressed->button)
|
||||||
|
{
|
||||||
|
case sf::Mouse::Button::Right:
|
||||||
|
polygons.emplace_back(constructRectangle((sf::Vector2f)mousePressed->position, { polySize[0], polySize[1] }, sf::Color::Black));
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (const auto* mouseWheelScrolled = event->getIf<sf::Event::MouseWheelScrolled>())
|
||||||
|
{
|
||||||
|
switch (mouseWheelScrolled->wheel)
|
||||||
|
{
|
||||||
|
case sf::Mouse::Wheel::Vertical:
|
||||||
|
if (boundedLight)
|
||||||
|
lightCenterAngle = std::clamp(lightCenterAngle += (int)mouseWheelScrolled->delta, 0, 360);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (const auto* mouseMoved = event->getIf<sf::Event::MouseMoved>())
|
||||||
|
{
|
||||||
|
mousePos = (sf::Vector2f)mouseMoved->position;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void processRays()
|
||||||
|
{
|
||||||
|
if (numRays > 0)
|
||||||
|
{
|
||||||
|
float i = 0.f, angleIncrement = 360.f / (float)numRays;
|
||||||
|
for (int i = 0; i < numRays; i++) rays.emplace_back(Ray(mousePos, rayLength, sf::degrees(angleIncrement * i), rayColor.asSfColor()));
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto& poly : polygons)
|
||||||
|
{
|
||||||
|
for (std::size_t i = 0; i < poly.getVertexCount() - 1; i++)
|
||||||
|
{
|
||||||
|
if (distanceBetween(mousePos, poly[i].position) <= rayLength)
|
||||||
|
{
|
||||||
|
sf::Angle angle = sf::radians(std::atan2f(poly[i].position.y - mousePos.y, poly[i].position.x - mousePos.x));
|
||||||
|
rays.emplace_back(Ray(mousePos, poly[i].position, rayColor.asSfColor()));
|
||||||
|
rays.emplace_back(Ray(mousePos, rayLength, angle + sf::radians(.00001f), rayColor.asSfColor()));
|
||||||
|
rays.emplace_back(Ray(mousePos, rayLength, angle - sf::radians(.00001f), rayColor.asSfColor()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto& ray : rays)
|
||||||
|
{
|
||||||
|
ray.calculateIntersect(polygons);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void render()
|
||||||
|
{
|
||||||
|
window.clear(sf::Color::White);
|
||||||
|
|
||||||
|
light.processRays(polygons);
|
||||||
|
light.draw(window);
|
||||||
|
|
||||||
|
for (auto& poly : polygons) window.draw(poly);
|
||||||
|
|
||||||
|
if (drawRays)
|
||||||
|
{
|
||||||
|
for (auto& ray : rays)
|
||||||
|
{
|
||||||
|
auto& rayPoints = ray.points();
|
||||||
|
sf::CircleShape endPoint(5.f, 20u);
|
||||||
|
endPoint.setOrigin({ 5, 5 });
|
||||||
|
endPoint.setFillColor(rayColor.asSfColor());
|
||||||
|
endPoint.setPosition(rayPoints[end].position);
|
||||||
|
window.draw(rayPoints);
|
||||||
|
window.draw(endPoint);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui::SFML::Render(window);
|
||||||
|
|
||||||
|
window.display();
|
||||||
|
}
|
||||||
|
|
@ -142,10 +142,12 @@
|
||||||
<ClCompile Include="..\..\..\..\..\dev\libraries\imgui\imgui_draw.cpp" />
|
<ClCompile Include="..\..\..\..\..\dev\libraries\imgui\imgui_draw.cpp" />
|
||||||
<ClCompile Include="..\..\..\..\..\dev\libraries\imgui\imgui_tables.cpp" />
|
<ClCompile Include="..\..\..\..\..\dev\libraries\imgui\imgui_tables.cpp" />
|
||||||
<ClCompile Include="..\..\..\..\..\dev\libraries\imgui\imgui_widgets.cpp" />
|
<ClCompile Include="..\..\..\..\..\dev\libraries\imgui\imgui_widgets.cpp" />
|
||||||
|
<ClCompile Include="Light.cpp" />
|
||||||
<ClCompile Include="main.cpp" />
|
<ClCompile Include="main.cpp" />
|
||||||
<ClCompile Include="Ray.cpp" />
|
<ClCompile Include="Ray.cpp" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<ClInclude Include="Light.h" />
|
||||||
<ClInclude Include="Utility.hpp" />
|
<ClInclude Include="Utility.hpp" />
|
||||||
<ClInclude Include="Random.h" />
|
<ClInclude Include="Random.h" />
|
||||||
<ClInclude Include="Ray.h" />
|
<ClInclude Include="Ray.h" />
|
||||||
|
|
|
||||||
|
|
@ -45,6 +45,9 @@
|
||||||
<ClCompile Include="Ray.cpp">
|
<ClCompile Include="Ray.cpp">
|
||||||
<Filter>Source Files\Classes</Filter>
|
<Filter>Source Files\Classes</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
<ClCompile Include="Light.cpp">
|
||||||
|
<Filter>Source Files\Classes</Filter>
|
||||||
|
</ClCompile>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClInclude Include="Utility.hpp">
|
<ClInclude Include="Utility.hpp">
|
||||||
|
|
@ -56,5 +59,8 @@
|
||||||
<ClInclude Include="Ray.h">
|
<ClInclude Include="Ray.h">
|
||||||
<Filter>Header Files\Classes</Filter>
|
<Filter>Header Files\Classes</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
<ClInclude Include="Light.h">
|
||||||
|
<Filter>Header Files\Classes</Filter>
|
||||||
|
</ClInclude>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
</Project>
|
</Project>
|
||||||
Loading…
Reference in New Issue