1
0
Fork 0

Compare commits

..

3 commits

Author SHA1 Message Date
e234dda860 Colors: Introduce color type abstraction
SFML and Dear ImGui have incompatible color types, abstract them through
a new Color class which has conversions.

Centralize color constants in a namespace as well.
2024-01-26 23:07:25 +00:00
b492def96e Debug: Introduce Dear ImGui interfaces
Introduce Dear ImGui to the CMakeBuild, allow building without it.

Add two debug interfaces : one FPS counter and frame time graph,
one map visualizer and editor.
2024-01-26 23:05:11 +00:00
92daf5551f World: Rename wallColor to fillColor
As this function will get more generic, make the names more generic.

Fix some comments and indentation.
2024-01-26 21:34:13 +00:00
5 changed files with 205 additions and 15 deletions

View file

@ -11,8 +11,28 @@ if(NOT SFML_FOUND)
message(FATAL_ERROR "SFML could not be found") message(FATAL_ERROR "SFML could not be found")
endif() endif()
add_executable(raycasting main.cpp Player.cpp Player.h World.cpp World.h) set(LIBS
target_link_libraries(raycasting
sfml-window sfml-window
sfml-graphics) sfml-graphics)
find_package(ImGui QUIET)
find_package(ImGui-SFML QUIET)
if(NOT ImGui_FOUND OR NOT ImGui-SFML_FOUND OR NO_IMGUI)
message("*Not* building with ImGui")
else ()
message("Building with ImGui")
add_compile_definitions(IMGUI)
set(LIBS ${LIBS}
ImGui-SFML::ImGui-SFML)
endif()
add_compile_options(-Wall -Wextra)
add_executable(raycasting
main.cpp
Player.cpp
World.cpp
)
target_link_libraries(raycasting ${LIBS})

37
Color.h Normal file
View file

@ -0,0 +1,37 @@
//
// Created by trotfunky on 26/01/24.
//
#ifndef RAYCASTING_COLOR_H
#define RAYCASTING_COLOR_H
#include <SFML/Graphics.hpp>
#ifdef IMGUI
#include <imgui.h>
#endif
class Color {
public:
uint8_t r;
uint8_t g;
uint8_t b;
uint8_t alpha;
constexpr Color(uint8_t r, uint8_t g, uint8_t b, uint8_t alpha = 255) :
r(r), g(g), b(b), alpha(alpha) {};
operator sf::Color() const { return {r, g, b, alpha}; }
#ifdef IMGUI
operator ImColor() const { return {r, g, b, alpha}; }
#endif
};
namespace Colors {
static constexpr Color Ground{67, 137, 39};
static constexpr Color Ceiling{39, 69, 137};
static constexpr Color Wall{84, 56, 34};
static constexpr Color Door{186, 152, 107};
static constexpr Color Window{104, 123, 165};
}
#endif //RAYCASTING_COLOR_H

View file

@ -5,6 +5,10 @@
#include "World.h" #include "World.h"
#include <cmath> #include <cmath>
#ifdef IMGUI
#include <imgui.h>
#include <imgui-SFML.h>
#endif
World::World(int w, int h, sf::Color groundColor, sf::Color ceilingColor, std::vector<BlockType> worldMap) : World::World(int w, int h, sf::Color groundColor, sf::Color ceilingColor, std::vector<BlockType> worldMap) :
player(0,0,0), w(w), h(h), map(std::move(worldMap)), player(0,0,0), w(w), h(h), map(std::move(worldMap)),
@ -205,13 +209,13 @@ float World::castRay(float originX, float originY, float orientation) const
} }
void World::fillColumn(sf::RenderWindow& window, unsigned int column, void World::fillColumn(sf::RenderWindow& window, unsigned int column,
float scale, sf::Color wallColor) const float scale, sf::Color fillColor) const
{ {
float columnHeight = static_cast<float>(window.getSize().y)*scale; float columnHeight = static_cast<float>(window.getSize().y)*scale;
sf::RectangleShape pixelColumn(sf::Vector2f(1,columnHeight)); sf::RectangleShape pixelColumn(sf::Vector2f(1,columnHeight));
pixelColumn.setPosition(static_cast<float>(column), pixelColumn.setPosition(static_cast<float>(column),
(static_cast<float>(window.getSize().y)-columnHeight)/2.0f); (static_cast<float>(window.getSize().y)-columnHeight)/2.0f);
pixelColumn.setFillColor(wallColor); pixelColumn.setFillColor(fillColor);
window.draw(pixelColumn); window.draw(pixelColumn);
} }
@ -249,7 +253,7 @@ void World::render(sf::RenderWindow& window) const
rayAngle -= 360; rayAngle -= 360;
} }
float obstacleScale = player.focalLength*2/(castRay(player.x, player.y, rayAngle)*player.sensorSize); float obstacleScale = player.focalLength*2/(castRay(player.x, player.y, rayAngle)*player.sensorSize);
/* 2 Is wall height in meters. */ /* 2 Is wall height in meters. */
fillColumn(window, i, obstacleScale); fillColumn(window, i, obstacleScale);
} }
} }
@ -263,4 +267,77 @@ void World::step(const float& stepTime) {
-player.currentMoveSpeedY*stepTime); -player.currentMoveSpeedY*stepTime);
} }
player.rotate(player.currentRotationSpeed*stepTime); player.rotate(player.currentRotationSpeed*stepTime);
#ifdef IMGUI
ImGui::Begin("MapEdit");
static int blockToPlace = 1;
/*
* Group all the select boxes together : makes it a big block in the
* Dear ImGui layout an allows adding things on the side.
*/
ImGui::BeginGroup();
for (int y = 0 ; y < h ; y++) {
for (int x = 0 ; x < w ; x++) {
ImGui::PushID(x + y*w);
if (x > 0)
ImGui::SameLine();
BlockType currentBlock = map[x + w*y];
ImVec4 hoverColor;
switch ((BlockType)blockToPlace) {
case BlockType::WALL:
hoverColor = (ImVec4)Colors::Wall;
break;
case BlockType::DOOR:
hoverColor = (ImVec4)Colors::Door;
break;
case BlockType::WINDOW:
hoverColor = (ImVec4)Colors::Window;
break;
default:
/* Default header color, it seems ? */
hoverColor = (ImVec4)ImColor(188, 120, 32);
break;
}
ImGui::PushStyleColor(ImGuiCol_HeaderHovered, hoverColor);
ImVec4 blockColor;
switch (currentBlock) {
case BlockType::WALL:
blockColor = (ImVec4)Colors::Wall;
break;
case BlockType::DOOR:
blockColor = (ImVec4)Colors::Door;
break;
case BlockType::WINDOW:
blockColor = (ImVec4)Colors::Window;
break;
default:
blockColor = (ImVec4)ImColor(188, 120, 32);
break;
}
ImGui::PushStyleColor(ImGuiCol_Header, blockColor);
if(ImGui::Selectable("", currentBlock != BlockType::AIR, 0, ImVec2(10, 10))) {
map[x + w*y] = currentBlock == (BlockType)blockToPlace ? BlockType::AIR : (BlockType)blockToPlace;
}
ImGui::PopStyleColor(2);
ImGui::PopID();
}
}
ImGui::EndGroup();
ImGui::SameLine();
ImGui::BeginGroup();
ImGui::Indent();
ImGui::Text("Place :");
ImGui::RadioButton("Wall", &blockToPlace, (int)BlockType::WALL);
ImGui::RadioButton("Door", &blockToPlace, (int)BlockType::DOOR);
ImGui::RadioButton("Window", &blockToPlace, (int)BlockType::WINDOW);
ImGui::Unindent();
ImGui::EndGroup();
ImGui::End();
#endif
} }

View file

@ -10,6 +10,7 @@
#include <SFML/Graphics.hpp> #include <SFML/Graphics.hpp>
#include <iostream> #include <iostream>
#include "Color.h"
#include "Player.h" #include "Player.h"
enum class BlockType { enum class BlockType {
@ -24,8 +25,8 @@ public:
Player player; Player player;
World(int w, int h, World(int w, int h,
sf::Color groundColor = sf::Color{67, 137, 39}, sf::Color groundColor = Colors::Ground,
sf::Color ceilingColor = sf::Color{39, 69, 137}, sf::Color ceilingColor = Colors::Ceiling,
std::vector<BlockType> worldMap = {}); std::vector<BlockType> worldMap = {});
int getW() const; int getW() const;
int getH() const; int getH() const;
@ -52,9 +53,9 @@ private:
sf::Color ceilingColor; sf::Color ceilingColor;
void fillColumn(sf::RenderWindow&, unsigned int column, float scale, void fillColumn(sf::RenderWindow&, unsigned int column, float scale,
sf::Color wallColor = sf::Color(84,56,34)) const; sf::Color fillColor = Colors::Wall) const;
/** /**
* Cast a ray from a given position and its distance to the origin. * Cast a ray from a given position and return its distance to the origin.
* @param originX Ray X origin, strictly positive * @param originX Ray X origin, strictly positive
* @param originY Ray Y origin, strictly positive * @param originY Ray Y origin, strictly positive
* @param orientation Angle to cast to, in degrees between 0 and 360 * @param orientation Angle to cast to, in degrees between 0 and 360

View file

@ -1,20 +1,35 @@
#include <iostream> #include <iostream>
#include <SFML/Graphics.hpp> #include <SFML/Graphics.hpp>
#ifdef IMGUI
#include <imgui.h>
#include <imgui-SFML.h>
#endif
#include "World.h" #include "World.h"
// TODO: Find a way to go to edges instead of just equally split (?) // TODO: Find a way to go to edges instead of just equally split (?)
int main() int main()
{ {
World world(10,10); World world(32,32);
world.setBlock(BlockType::AIR,1,1,8,8); world.setBlock(BlockType::AIR,1,1,30,30);
world.setBlock(BlockType::WALL,4,4,2,2); world.setBlock(BlockType::WALL,4,4,2,2);
world.player.move(2,2); world.player.move(2,2);
std::cout << world << std::endl; std::cout << world << std::endl;
sf::RenderWindow window(sf::VideoMode(800,600),"Da raycasting");
sf::RenderWindow window(sf::VideoMode(1000,1000),"Da raycasting"); sf::RenderWindow window(sf::VideoMode(1000,1000),"Da raycasting");
#ifdef IMGUI
if (!ImGui::SFML::Init(window)) {
std::cout << "Failed to init Dear ImGui SFML" << std::endl;
return -1;
}
sf::Clock fpsDataClock;
float frameTimings[100];
unsigned int frameCount = 0;
#endif
// window.setFramerateLimit(60);
sf::Event event{}; sf::Event event{};
sf::Clock frameTime; sf::Clock frameTime;
@ -34,6 +49,13 @@ int main()
window.setView(sf::View(newView)); window.setView(sf::View(newView));
continue; continue;
} }
#ifdef IMGUI
ImGui::SFML::ProcessEvent(window, event);
// Check if Dear ImGui should process the key events.
ImGuiIO& io = ImGui::GetIO();
if (io.WantCaptureMouse || io.WantCaptureKeyboard)
continue;
#endif
if (event.type == sf::Event::KeyPressed) { if (event.type == sf::Event::KeyPressed) {
switch (event.key.code) { switch (event.key.code) {
case sf::Keyboard::Key::Escape: case sf::Keyboard::Key::Escape:
@ -71,11 +93,44 @@ int main()
} }
} }
window.clear(); window.clear();
const sf::Time& deltaT = frameTime.restart();
world.step(frameTime.restart().asSeconds()); #ifdef IMGUI
ImGui::SFML::Update(window, deltaT);
#endif
world.step(deltaT.asSeconds());
world.render(window); world.render(window);
#ifdef IMGUI
// ImGui::ShowDemoWindow();
ImGuiWindowFlags window_flags = ImGuiWindowFlags_NoDecoration
| ImGuiWindowFlags_AlwaysAutoResize
| ImGuiWindowFlags_NoSavedSettings
| ImGuiWindowFlags_NoFocusOnAppearing
| ImGuiWindowFlags_NoNav;
ImVec2 window_area = ImGui::GetMainViewport()->WorkSize;
ImGui::SetNextWindowPos({window_area.x - 20, 20}, ImGuiCond_Always, {1,0});
ImGui::SetNextWindowBgAlpha(0.2f);
ImGui::Begin("FPS", nullptr ,window_flags);
if (fpsDataClock.getElapsedTime().asMilliseconds() > 20) {
frameTimings[frameCount%100] = static_cast<float>(deltaT.asMicroseconds());
frameCount++;
fpsDataClock.restart();
}
ImGui::Text("FPS : %d", (int)(1.0/deltaT.asSeconds()));
ImGui::PlotLines("µs", frameTimings, frameCount >= 100 ? 100 : frameCount);
ImGui::End();
ImGui::SFML::Render(window);
#endif
window.display(); window.display();
} }
#ifdef IMGUI
ImGui::SFML::Shutdown();
#endif
return 0; return 0;
} }