270 lines
6.8 KiB
C++
270 lines
6.8 KiB
C++
#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"
|
|
#include "Light.h"
|
|
|
|
|
|
auto window = sf::RenderWindow(sf::VideoMode({ 1920u, 1080u }), "Ray Casting Test");
|
|
|
|
Light light;
|
|
std::vector<sf::VertexArray> polygons;
|
|
|
|
sf::Vector2f mousePos{};
|
|
sf::Vector2f center{ 1920.f / 2.f, 1080.f / 2.f };
|
|
|
|
//imGui Variables
|
|
constexpr int numRaysBounds[2] = { 5, 500 };
|
|
constexpr float rayLengthBounds[2] = {5.f, 5000.f};
|
|
constexpr float offsetAngleBounds[2] = { 5.f, 175.f };
|
|
constexpr int vertexMin{ 3 };
|
|
constexpr int vertexMax{ 20 };
|
|
constexpr float rotationSpeedScale{ 3.f };
|
|
float polySize[2] = { 100.f, 100.f };
|
|
int numRays{ 500 };
|
|
int vertexBounds[2] = { 3, 10 };
|
|
int averageSize{ 100 };
|
|
float rayLength{ 500.f };
|
|
imguiColor rayColor = constructImguiColor(sf::Color::Red);
|
|
imguiColor lightColor = constructImguiColor(sf::Color::Yellow);
|
|
imguiColor endPointColor = constructImguiColor(sf::Color::Magenta);
|
|
bool drawRays{ false };
|
|
bool drawLight{ true };
|
|
bool drawEndPoints{ false };
|
|
bool boundedLight{ false };
|
|
bool infiniteRayLength{ false };
|
|
float lightCenterAngle{ 0.f };
|
|
float lightOffsetAngle{ 45.f };
|
|
|
|
void GUI();
|
|
void userInput();
|
|
void render();
|
|
|
|
int main()
|
|
{
|
|
//configure light with default imgui vatiables
|
|
drawRays ? light.setFlags(Light::Flags::drawRays) : light.unsetFlags(Light::Flags::drawRays);
|
|
drawLight ? light.setFlags(Light::Flags::visibility) : light.unsetFlags(Light::Flags::visibility);
|
|
drawEndPoints ? light.setFlags(Light::Flags::drawEndPoints) : light.unsetFlags(Light::Flags::drawEndPoints);
|
|
infiniteRayLength ? light.setFlags(Light::Flags::infiniteLength) : light.unsetFlags(Light::Flags::infiniteLength);
|
|
|
|
//sfml setup
|
|
sf::Clock clock;
|
|
window.setFramerateLimit(144);
|
|
if (!ImGui::SFML::Init(window))
|
|
return -1;
|
|
|
|
mousePos = center;
|
|
|
|
polygons.emplace_back(constructRectangle(center, center));
|
|
|
|
//main game loop
|
|
while (window.isOpen())
|
|
{
|
|
ImGui::SFML::Update(window, clock.restart());
|
|
|
|
light.clearRays();
|
|
|
|
userInput();
|
|
|
|
GUI();
|
|
|
|
light.setOrigin(mousePos);
|
|
light.processRays(polygons);
|
|
|
|
render();
|
|
|
|
}
|
|
|
|
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();
|
|
if (ImGui::Checkbox("Render rays", &drawRays))
|
|
{
|
|
light.toggleFlags(Light::Flags::drawRays);
|
|
}
|
|
|
|
ImGui::SameLine();
|
|
if (ImGui::Checkbox("Render end points", &drawEndPoints))
|
|
{
|
|
light.toggleFlags(Light::Flags::drawEndPoints);
|
|
}
|
|
|
|
ImGui::SameLine();
|
|
if (ImGui::Checkbox("Render light", &drawLight))
|
|
{
|
|
light.toggleFlags(Light::Flags::visibility);
|
|
}
|
|
|
|
if (ImGui::Checkbox("Infinite ray length", &infiniteRayLength))
|
|
{
|
|
light.toggleFlags(Light::Flags::infiniteLength);
|
|
}
|
|
|
|
if (not infiniteRayLength)
|
|
{
|
|
ImGui::SliderInt("number of rays", &numRays, numRaysBounds[0], numRaysBounds[1]);
|
|
light.setRayCount(numRays);
|
|
|
|
if (ImGui::InputFloat("Ray Length", &rayLength))
|
|
{
|
|
rayLength = std::clamp(rayLength, rayLengthBounds[0], rayLengthBounds[1]);
|
|
}
|
|
light.setRayLength(rayLength);
|
|
}
|
|
|
|
if (drawRays)
|
|
{
|
|
ImGui::ColorEdit4("Ray color", &rayColor.r);
|
|
}
|
|
|
|
if (drawLight)
|
|
{
|
|
ImGui::ColorEdit4("Light color", &lightColor.r);
|
|
}
|
|
|
|
if (drawEndPoints)
|
|
{
|
|
ImGui::ColorEdit4("End point color", &endPointColor.r);
|
|
}
|
|
light.changeLightColor(lightColor.asSfColor());
|
|
light.changeEndPointColor(endPointColor.asSfColor());
|
|
light.changeRayColor(rayColor.asSfColor());
|
|
|
|
if(ImGui::Checkbox("Light is bounded", &boundedLight))
|
|
{
|
|
boundedLight ? light.addAngleBounds(sf::degrees(lightCenterAngle), sf::degrees(lightOffsetAngle)) : light.removeAngleBounds();
|
|
}
|
|
|
|
if (boundedLight)
|
|
{
|
|
ImGui::SliderFloat("Light direction", &lightCenterAngle, 0.f, 359.f, "%.0f", ImGuiSliderFlags_::ImGuiSliderFlags_AlwaysClamp);
|
|
light.setCenterAngle(sf::degrees(lightCenterAngle));
|
|
|
|
ImGui::SliderFloat("Offset size", &lightOffsetAngle, offsetAngleBounds[0], offsetAngleBounds[1], "%.0f", ImGuiSliderFlags_::ImGuiSliderFlags_AlwaysClamp);
|
|
light.setOffsetAngle(sf::degrees(lightOffsetAngle));
|
|
}
|
|
|
|
ImGui::InputFloat2("rectangle Size (X,Y)", polySize, "%.1f");
|
|
ImGui::Text("Random polygon config: ");
|
|
if (ImGui::SliderInt2("vertex count lower/upper bounds", vertexBounds, vertexMin, vertexMax))
|
|
{
|
|
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()
|
|
{
|
|
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();
|
|
polygons.emplace_back(constructRectangle(center, center));
|
|
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 += mouseWheelScrolled->delta * rotationSpeedScale;
|
|
if (lightCenterAngle > 359.f) lightCenterAngle = 0.f;
|
|
if (lightCenterAngle < 0.f) lightCenterAngle = 359.f;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (const auto* mouseMoved = event->getIf<sf::Event::MouseMoved>())
|
|
{
|
|
mousePos = (sf::Vector2f)mouseMoved->position;
|
|
}
|
|
}
|
|
}
|
|
|
|
void render()
|
|
{
|
|
window.clear(sf::Color::White);
|
|
|
|
light.draw(window);
|
|
|
|
for (auto& poly : polygons) window.draw(poly);
|
|
|
|
ImGui::SFML::Render(window);
|
|
|
|
window.display();
|
|
} |