diff options
Diffstat (limited to 'ui')
33 files changed, 277 insertions, 510 deletions
diff --git a/ui/builders/freeExtend.cpp b/ui/builders/freeExtend.cpp index ab5a998..aff7cd7 100644 --- a/ui/builders/freeExtend.cpp +++ b/ui/builders/freeExtend.cpp @@ -16,17 +16,17 @@ BuilderFreeExtend::move( { if (p1) { if (const auto p = network->intersectRayNodes(ray)) { - candidateLinks.objects = network->candidateJoins(*p1, p->pos); + candidateLinks = network->candidateJoins(*p1, p->pos); } else if (const auto p = geoData->intersectRay(ray)) { - candidateLinks.objects = network->candidateExtend(*p1, p->first); + candidateLinks = network->candidateExtend(*p1, p->first); } else { - candidateLinks.removeAll(); + candidateLinks.clear(); } } else { - candidateLinks.removeAll(); + candidateLinks.clear(); } } diff --git a/ui/builders/join.cpp b/ui/builders/join.cpp index 6941e23..f6cbce5 100644 --- a/ui/builders/join.cpp +++ b/ui/builders/join.cpp @@ -15,10 +15,10 @@ BuilderJoin::move(Network * network, const GeoData *, const SDL_MouseMotionEvent { if (p1) { if (const auto p = network->intersectRayNodes(ray)) { - candidateLinks.objects = network->candidateJoins(p1->pos, p->pos); + candidateLinks = network->candidateJoins(p1->pos, p->pos); } else { - candidateLinks.removeAll(); + candidateLinks.clear(); } } } @@ -33,7 +33,7 @@ BuilderJoin::click( if (p1) { create(network, geoData, p1, p); p1.reset(); - candidateLinks.removeAll(); + candidateLinks.clear(); } else { p1 = p; diff --git a/ui/builders/straight.cpp b/ui/builders/straight.cpp index 338aa8a..e7d83b5 100644 --- a/ui/builders/straight.cpp +++ b/ui/builders/straight.cpp @@ -17,10 +17,10 @@ BuilderStraight::move( { if (p1) { if (const auto p = geoData->intersectRay(ray)) { - candidateLinks.objects = network->candidateStraight(*p1, p->first); + candidateLinks = network->candidateStraight(*p1, p->first); } else { - candidateLinks.removeAll(); + candidateLinks.clear(); } } } @@ -34,7 +34,7 @@ BuilderStraight::click( if (const auto p = geoData->intersectRay(ray)) { if (p1) { create(network, geoData, *p1, p->first); - candidateLinks.removeAll(); + candidateLinks.clear(); p1.reset(); } else { @@ -44,7 +44,7 @@ BuilderStraight::click( return; case SDL_BUTTON_MIDDLE: p1.reset(); - candidateLinks.removeAll(); + candidateLinks.clear(); return; } } diff --git a/ui/editNetwork.cpp b/ui/editNetwork.cpp index 2887491..c900191 100644 --- a/ui/editNetwork.cpp +++ b/ui/editNetwork.cpp @@ -2,25 +2,15 @@ #include "builders/freeExtend.h" #include "builders/join.h" #include "builders/straight.h" -#include "text.h" +#include "imgui_wrap.h" #include <game/gamestate.h> #include <game/terrain.h> #include <gfx/gl/sceneShader.h> #include <gfx/models/texture.h> -const std::filesystem::path fontpath {"/usr/share/fonts/hack/Hack-Regular.ttf"}; constexpr const glm::u8vec4 TRANSPARENT_BLUE {30, 50, 255, 200}; -EditNetwork::EditNetwork(Network * n) : - network {n}, - builderToolbar { - {"ui/icon/network.png", mode.toggle<BuilderStraight>()}, - {"ui/icon/network.png", mode.toggle<BuilderJoin>()}, - {"ui/icon/network.png", mode.toggle<BuilderFreeExtend>()}, - }, - blue {1, 1, &TRANSPARENT_BLUE}, font {fontpath, 15} -{ -} +EditNetwork::EditNetwork(Network * n) : network {n}, blue {1, 1, &TRANSPARENT_BLUE} { } bool EditNetwork::click(const SDL_MouseButtonEvent & e, const Ray<GlobalPosition3D> & ray) @@ -42,9 +32,9 @@ EditNetwork::move(const SDL_MouseMotionEvent & e, const Ray<GlobalPosition3D> & } bool -EditNetwork::handleInput(const SDL_Event & e, const UIComponent::Position & parentPos) +EditNetwork::handleInput(const SDL_Event &) { - return builderToolbar.handleInput(e, parentPos); + return false; } void @@ -75,10 +65,20 @@ EditNetwork::Builder::setHeightsFor(Network * network, const Link::CCollection & } void -EditNetwork::render(const UIShader & shader, const UIComponent::Position & parentPos) const +EditNetwork::render(bool & open) { - if (builder) { - Text {builder->hint(), font, {{50, 10}, {0, 15}}, {1, 1, 0}}.render(shader, parentPos); - } - builderToolbar.render(shader, parentPos); + ImGui::SetNextWindowSize({-1, -1}); + ImGui::Begin("Edit Network", &open); + + auto builderChoice = [this]<typename Impl>(const char * name) { + if (ImGui::RadioButton(name, dynamic_cast<Impl *>(builder.get()))) { + builder = std::make_unique<Impl>(); + } + }; + builderChoice.operator()<BuilderStraight>("Straight"); + builderChoice.operator()<BuilderJoin>("Join"); + builderChoice.operator()<BuilderFreeExtend>("Free Extend"); + ImGui::TextUnformatted(builder ? builder->hint().c_str() : "Select a build mode"); + + ImGui::End(); } diff --git a/ui/editNetwork.h b/ui/editNetwork.h index ae887bd..4155534 100644 --- a/ui/editNetwork.h +++ b/ui/editNetwork.h @@ -2,8 +2,6 @@ #include "game/geoData.h" #include "gameMainSelector.h" -#include "modeHelper.h" -#include "toolbar.h" #include "worldOverlay.h" #include <game/gamestate.h> #include <game/network/network.h> @@ -17,9 +15,9 @@ public: bool click(const SDL_MouseButtonEvent & e, const Ray<GlobalPosition3D> &) override; bool move(const SDL_MouseMotionEvent & e, const Ray<GlobalPosition3D> &) override; - bool handleInput(const SDL_Event & e, const UIComponent::Position &) override; + bool handleInput(const SDL_Event & e) override; void render(const SceneShader &, const Frustum &) const override; - void render(const UIShader & shader, const UIComponent::Position & pos) const override; + void render(bool & open) override; using NetworkClickPos = std::variant<GlobalPosition3D, Node::Ptr>; @@ -36,16 +34,13 @@ public: using Ptr = std::unique_ptr<Builder>; protected: - Collection<const Link> candidateLinks; + SharedCollection<const Link> candidateLinks; }; private: Network * network; Builder::Ptr builder; - Mode<Builder::Ptr, ModeSecondClick::NoAction> mode {builder}; - Toolbar builderToolbar; Texture blue; - const Font font; }; template<typename T> class EditNetworkOf : public EditNetwork { diff --git a/ui/gameMainSelector.cpp b/ui/gameMainSelector.cpp index 23ae8c0..0c40abc 100644 --- a/ui/gameMainSelector.cpp +++ b/ui/gameMainSelector.cpp @@ -1,6 +1,4 @@ #include "gameMainSelector.h" -#include "collection.h" -#include "text.h" #include "ui/uiComponent.h" #include <SDL2/SDL.h> #include <game/gamestate.h> @@ -8,27 +6,21 @@ #include <game/terrain.h> #include <game/worldobject.h> // IWYU pragma: keep #include <gfx/camera.h> -#include <optional> #include <stream_support.h> -#include <typeinfo> -const std::filesystem::path fontpath {"/usr/share/fonts/hack/Hack-Regular.ttf"}; - -GameMainSelector::GameMainSelector(const Camera * c, ScreenAbsCoord size) : - UIComponent {{{}, size}}, camera {c}, font {fontpath, 15} -{ -} +GameMainSelector::GameMainSelector(const Camera * c) : camera {c} { } constexpr ScreenAbsCoord TargetPos {5, 45}; void -GameMainSelector::render(const UIShader & shader, const Position & parentPos) const +GameMainSelector::render() { if (target) { - target->render(shader, parentPos + position + TargetPos); - } - if (!clicked.empty()) { - Text {clicked, font, {{50, 10}, {0, 15}}, {1, 1, 0}}.render(shader, parentPos); + bool open = true; + target->render(open); + if (!open) { + target.reset(); + } } } @@ -41,10 +33,12 @@ GameMainSelector::render(const SceneShader & shader, const Frustum & frustum) co } bool -GameMainSelector::handleInput(const SDL_Event & e, const Position & parentPos) +GameMainSelector::handleInput(const SDL_Event & e) { - const auto getRay = [this](const auto & e) { - const auto mouse = ScreenRelCoord {e.x, e.y} / position.size; + const auto getRay = [this, &window = e.window](const auto & e) { + glm::ivec2 size {}; + SDL_GetWindowSizeInPixels(SDL_GetWindowFromID(window.windowID), &size.x, &size.y); + const auto mouse = ScreenRelCoord {e.x, e.y} / ScreenRelCoord {size}; return camera->unProject(mouse); }; if (target) { @@ -60,7 +54,7 @@ GameMainSelector::handleInput(const SDL_Event & e, const Position & parentPos) } break; } - return target->handleInput(e, parentPos + position + TargetPos); + return target->handleInput(e); } else { switch (e.type) { @@ -73,22 +67,8 @@ GameMainSelector::handleInput(const SDL_Event & e, const Position & parentPos) } void -GameMainSelector::defaultClick(const Ray<GlobalPosition3D> & ray) +GameMainSelector::defaultClick(const Ray<GlobalPosition3D> &) { - BaryPosition baryPos {}; - RelativeDistance distance {}; - - if (const auto selected = gameState->world.applyOne<Selectable>(&Selectable::intersectRay, ray, baryPos, distance); - selected != gameState->world.end()) { - const auto & ref = *selected.base()->get(); - clicked = typeid(ref).name(); - } - else if (const auto pos = gameState->terrain->intersectRay(ray)) { - clicked = streamed_string(*pos); - } - else { - clicked.clear(); - } } bool @@ -104,13 +84,13 @@ GameMainSelector::Component::move(const SDL_MouseMotionEvent &, const Ray<Global } bool -GameMainSelector::Component::handleInput(const SDL_Event &, const Position &) +GameMainSelector::Component::handleInput(const SDL_Event &) { return false; } void -GameMainSelector::Component::render(const UIShader &, const UIComponent::Position &) const +GameMainSelector::Component::render(bool &) { } diff --git a/ui/gameMainSelector.h b/ui/gameMainSelector.h index e715823..8c2be4b 100644 --- a/ui/gameMainSelector.h +++ b/ui/gameMainSelector.h @@ -2,16 +2,13 @@ #include "SDL_events.h" #include "config/types.h" -#include "font.h" #include "uiComponent.h" #include "worldOverlay.h" #include <glm/glm.hpp> #include <memory> -#include <string> class SceneShader; template<typename> class Ray; -class UIShader; class Camera; class GameMainSelector : public UIComponent, public WorldOverlay { @@ -22,17 +19,17 @@ public: virtual bool click(const SDL_MouseButtonEvent &, const Ray<GlobalPosition3D> &); virtual bool move(const SDL_MouseMotionEvent &, const Ray<GlobalPosition3D> &); - virtual bool handleInput(const SDL_Event &, const Position & pos); - virtual void render(const UIShader & shader, const Position & pos) const; + virtual bool handleInput(const SDL_Event &); + virtual void render(bool & open); virtual void render(const SceneShader &, const Frustum &) const; }; - GameMainSelector(const Camera * c, ScreenAbsCoord size); + GameMainSelector(const Camera * c); - void render(const UIShader & shader, const Position & pos) const override; + void render() override; void render(const SceneShader & shader, const Frustum &) const override; - bool handleInput(const SDL_Event & e, const Position &) override; + bool handleInput(const SDL_Event & e) override; void defaultClick(const Ray<GlobalPosition3D> & ray); @@ -40,6 +37,4 @@ public: private: const Camera * camera; - const Font font; - std::string clicked; }; diff --git a/ui/gameMainWindow.cpp b/ui/gameMainWindow.cpp index d88bab5..cc74f66 100644 --- a/ui/gameMainWindow.cpp +++ b/ui/gameMainWindow.cpp @@ -1,10 +1,10 @@ #include "gameMainWindow.h" #include "editNetwork.h" #include "gameMainSelector.h" +#include "imgui_extras.h" #include "manualCameraController.h" -#include "modeHelper.h" -#include "toolbar.h" -#include "window.h" +#include "queryTool.h" +#include "svgIcon.h" #include <SDL2/SDL.h> #include <collection.h> #include <game/environment.h> @@ -17,22 +17,44 @@ #include <glm/glm.hpp> #include <memory> -class GameMainToolbar : Mode<decltype(GameMainSelector::target)>, public Toolbar { +class GameMainToolbar : public UIComponent { public: - explicit GameMainToolbar(GameMainSelector * gms_) : - Mode<decltype(GameMainSelector::target)> {gms_->target}, - Toolbar { - {"ui/icon/network.png", toggle<EditNetworkOf<RailLinks>>()}, + static constexpr auto TOOLBAR_HEIGHT = 54.F; + template<typename T> static constexpr T TOOLBAR_ICON_SIZE {32, 32}; + + explicit GameMainToolbar(GameMainSelector * gms) : gms {gms} { } + + void + render() override + { + if (IltGui::BeginToolbar("bottomBar", ImGuiDir_Down, TOOLBAR_HEIGHT)) { + if (ImGui::ImageButton("Build rails", *buildRailsIcon, TOOLBAR_ICON_SIZE<ImVec2>)) { + gms->target = std::make_unique<EditNetworkOf<RailLinks>>(); + } + if (ImGui::ImageButton("Query", *queryToolIcon, TOOLBAR_ICON_SIZE<ImVec2>)) { + gms->target = std::make_unique<QueryTool>(); + } + IltGui::EndToolbar(); } + } + + bool + handleInput(const SDL_Event &) override { + return false; } + +private: + SvgIcon buildRailsIcon {TOOLBAR_ICON_SIZE<ImageDimensions>, "ui/icon/rails.svg"}; + SvgIcon queryToolIcon {TOOLBAR_ICON_SIZE<ImageDimensions>, "ui/icon/magnifier.svg"}; + GameMainSelector * gms; }; -GameMainWindow::GameMainWindow(size_t w, size_t h) : WindowContent {w, h}, SceneRenderer {{w, h}, 0} +GameMainWindow::GameMainWindow(size_t w, size_t h) : SceneRenderer {{w, h}, 0} { uiComponents.create<ManualCameraController>(glm::vec2 {310'727'624, 494'018'810}); - auto gms = uiComponents.create<GameMainSelector>(&camera, ScreenAbsCoord {w, h}); - uiComponents.create<GameMainToolbar>(gms.get()); + auto gms = uiComponents.create<GameMainSelector>(&camera); + uiComponents.create<GameMainToolbar>(gms); } GameMainWindow::~GameMainWindow() { } @@ -69,18 +91,18 @@ GameMainWindow::render() const glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glDisable(GL_DEPTH_TEST); - uiComponents.apply(&UIComponent::render, uiShader, UIComponent::Position {}); + uiComponents.apply(&UIComponent::render); } void GameMainWindow::content(const SceneShader & shader, const Frustum & frustum) const { - for (const auto & [id, asset] : gameState->assets) { - if (const auto r = std::dynamic_pointer_cast<const Renderable>(asset)) { - r->render(shader, frustum); + for (const auto & [assetId, asset] : gameState->assets) { + if (const auto renderable = asset.getAs<const Renderable>()) { + renderable->render(shader, frustum); } } - gameState->world.apply<Renderable>(&Renderable::render, shader, frustum); + gameState->world.apply<const Renderable>(&Renderable::render, shader, frustum); uiComponents.apply<WorldOverlay>(&WorldOverlay::render, shader, frustum); } @@ -93,16 +115,16 @@ GameMainWindow::environment(const SceneShader &, const SceneRenderer & r) const void GameMainWindow::lights(const SceneShader & shader) const { - gameState->world.apply<Renderable>(&Renderable::lights, shader); + gameState->world.apply<const Renderable>(&Renderable::lights, shader); } void GameMainWindow::shadows(const ShadowMapper & shadowMapper, const Frustum & frustum) const { - for (const auto & [id, asset] : gameState->assets) { - if (const auto r = std::dynamic_pointer_cast<const Renderable>(asset)) { - r->shadows(shadowMapper, frustum); + for (const auto & [assetId, asset] : gameState->assets) { + if (const auto renderable = asset.getAs<const Renderable>()) { + renderable->shadows(shadowMapper, frustum); } } - gameState->world.apply<Renderable>(&Renderable::shadows, shadowMapper, frustum); + gameState->world.apply<const Renderable>(&Renderable::shadows, shadowMapper, frustum); } diff --git a/ui/icon.cpp b/ui/icon.cpp index c3b5078..0bdc91a 100644 --- a/ui/icon.cpp +++ b/ui/icon.cpp @@ -22,9 +22,10 @@ Icon::Icon(const Image & tex) : size {tex.width, tex.height} GL_RGBA, GL_UNSIGNED_BYTE, tex.data.data()); } -void -Icon::Bind() const +ImTextureID +Icon::operator*() const { - glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D, m_texture); + static_assert(sizeof(m_texture) <= sizeof(ImTextureID)); + // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast,performance-no-int-to-ptr) This is how ImGui works + return reinterpret_cast<ImTextureID>(*m_texture); } @@ -1,5 +1,6 @@ #pragma once +#include "imgui_wrap.h" #include <filesystem> #include <glArrays.h> #include <glm/glm.hpp> @@ -11,8 +12,8 @@ public: explicit Icon(const std::filesystem::path & fileName); explicit Icon(const Image & image); - void Bind() const; const glm::vec2 size; + ImTextureID operator*() const; private: glTexture m_texture; diff --git a/ui/iconButton.cpp b/ui/iconButton.cpp deleted file mode 100644 index fe8c817..0000000 --- a/ui/iconButton.cpp +++ /dev/null @@ -1,57 +0,0 @@ -#include "iconButton.h" -#include "glArrays.h" -#include "ui/icon.h" -#include "ui/uiComponent.h" -#include <SDL2/SDL.h> -#include <array> -#include <filesystem> -#include <functional> -#include <glad/gl.h> -#include <glm/gtc/type_ptr.hpp> -#include <utility> - -IconButton::IconButton(const std::string & icon_, glm::vec2 position_, UIEvent click_) : - UIComponent {{position_, ICON_SIZE}}, icon {icon_}, click {std::move(click_)} -{ - glBindVertexArray(m_vertexArrayObject); - - glBindBuffer(GL_ARRAY_BUFFER, m_vertexArrayBuffer); - glBufferData(GL_ARRAY_BUFFER, static_cast<GLsizeiptr>(sizeof(glm::vec4) * 4), nullptr, GL_DYNAMIC_DRAW); - - glEnableVertexAttribArray(0); - glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, sizeof(glm::vec4), nullptr); - - glBindVertexArray(0); -} - -void -IconButton::render(const UIShader &, const Position & parentPos) const -{ - icon.Bind(); - glBindVertexArray(m_vertexArrayObject); - glBindBuffer(GL_ARRAY_BUFFER, m_vertexArrayBuffer); - const auto abs = parentPos.origin + position.origin; - const auto limit = abs + ICON_SIZE; - std::array<glm::vec4, 4> vertices {{ - {abs.x, abs.y, 0, 0}, - {limit.x, abs.y, 1, 0}, - {limit.x, limit.y, 1, 1}, - {abs.x, limit.y, 0, 1}, - }}; - glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(vertices), glm::value_ptr(vertices.front())); - glDrawArrays(GL_TRIANGLE_FAN, 0, 4); - glBindBuffer(GL_ARRAY_BUFFER, 0); - glBindVertexArray(0); -} - -bool -IconButton::handleInput(const SDL_Event & e, const Position & parentPos) -{ - const auto absPos = position + parentPos; - if (absPos & e.button) { - if (e.button.type == SDL_MOUSEBUTTONUP && e.button.button == SDL_BUTTON_LEFT) { - click(e); - } - } - return false; -} diff --git a/ui/iconButton.h b/ui/iconButton.h deleted file mode 100644 index 0afe92d..0000000 --- a/ui/iconButton.h +++ /dev/null @@ -1,26 +0,0 @@ -#pragma once - -#include "icon.h" -#include "uiComponent.h" -#include <glArrays.h> -#include <glm/glm.hpp> -#include <string> - -class UIShader; -union SDL_Event; - -static const constexpr glm::vec2 ICON_SIZE {32.F, 32.F}; - -class IconButton : public UIComponent { -public: - IconButton(const std::string & icon, glm::vec2 position, UIEvent click); - - void render(const UIShader &, const Position & parentPos) const override; - - bool handleInput(const SDL_Event & e, const Position & parentPos) override; - - Icon icon; - UIEvent click; - glVertexArray m_vertexArrayObject; - glBuffer m_vertexArrayBuffer; -}; diff --git a/ui/imgui_extras.cpp b/ui/imgui_extras.cpp new file mode 100644 index 0000000..1643f4f --- /dev/null +++ b/ui/imgui_extras.cpp @@ -0,0 +1,33 @@ +#define IMGUI_INTERNAL +#include "imgui_extras.h" + +namespace IltGui { + bool + BeginToolbar(const char * name, ImGuiDir dir, float axisSize, ImGuiWindowFlags windowFlags) + { + return BeginToolbar(name, ImGui::GetMainViewport(), dir, axisSize, windowFlags); + } + + bool + BeginToolbar( + const char * name, ImGuiViewport * viewport, ImGuiDir dir, float axisSize, ImGuiWindowFlags windowFlags) + { + bool isOpen = ImGui::BeginViewportSideBar(name, viewport, dir, axisSize, + windowFlags | ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoSavedSettings); + if (isOpen) { + if (dir == ImGuiDir_Up || dir == ImGuiDir_Down) { + ImGui::GetCurrentWindow()->DC.LayoutType = ImGuiLayoutType_Horizontal; + } + } + else { + ImGui::End(); + } + return isOpen; + } + + void + EndToolbar() + { + ImGui::End(); + } +} diff --git a/ui/imgui_extras.h b/ui/imgui_extras.h new file mode 100644 index 0000000..0babaa3 --- /dev/null +++ b/ui/imgui_extras.h @@ -0,0 +1,10 @@ +#include "imgui_wrap.h" + +namespace IltGui { + // NOLINTBEGIN(readability-identifier-naming) + bool BeginToolbar(const char * name, ImGuiViewport * viewport, ImGuiDir dir, float axisSize, + ImGuiWindowFlags windowFlags = 0); + bool BeginToolbar(const char * name, ImGuiDir dir, float axisSize, ImGuiWindowFlags windowFlags = 0); + void EndToolbar(); + // NOLINTEND(readability-identifier-naming) +} diff --git a/ui/imgui_wrap.h b/ui/imgui_wrap.h index 1d619a4..520d8b8 100644 --- a/ui/imgui_wrap.h +++ b/ui/imgui_wrap.h @@ -3,4 +3,11 @@ #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wold-style-cast" #include "imgui.h" // IWYU pragma: export +#ifdef IMGUI_INTERNAL +# pragma GCC diagnostic push +# pragma GCC diagnostic ignored "-Wconversion" +# pragma GCC diagnostic ignored "-Wsign-conversion" +# include "imgui_internal.h" // IWYU pragma: export +# pragma GCC diagnostic pop +#endif #pragma GCC diagnostic pop diff --git a/ui/mainApplication.h b/ui/mainApplication.h index a6cb126..1489587 100644 --- a/ui/mainApplication.h +++ b/ui/mainApplication.h @@ -6,7 +6,7 @@ class MainApplication : public ApplicationBase { public: - using Windows = Collection<Window>; + using Windows = SharedCollection<Window>; void mainLoop(); protected: diff --git a/ui/manualCameraController.cpp b/ui/manualCameraController.cpp index fbd0ca3..553afc1 100644 --- a/ui/manualCameraController.cpp +++ b/ui/manualCameraController.cpp @@ -5,7 +5,7 @@ #include <maths.h> bool -ManualCameraController::handleInput(const SDL_Event & e, const Position &) +ManualCameraController::handleInput(const SDL_Event & e) { switch (e.type) { case SDL_KEYDOWN: @@ -72,7 +72,7 @@ ManualCameraController::handleInput(const SDL_Event & e, const Position &) } void -ManualCameraController::render(const UIShader &, const Position &) const +ManualCameraController::render() { } diff --git a/ui/manualCameraController.h b/ui/manualCameraController.h index 2f955e7..6501762 100644 --- a/ui/manualCameraController.h +++ b/ui/manualCameraController.h @@ -6,15 +6,14 @@ #include <glm/glm.hpp> #include <maths.h> -class UIShader; class Camera; class ManualCameraController : public CameraController, public UIComponent { public: - explicit ManualCameraController(GlobalPosition2D f) : UIComponent {{}}, focus {f} { } + explicit ManualCameraController(GlobalPosition2D f) : focus {f} { } - bool handleInput(const SDL_Event & e, const Position &) override; - void render(const UIShader &, const Position & parentPos) const override; + bool handleInput(const SDL_Event & e) override; + void render() override; void updateCamera(Camera * camera) const override; diff --git a/ui/modeHelper.h b/ui/modeHelper.h deleted file mode 100644 index d20f2db..0000000 --- a/ui/modeHelper.h +++ /dev/null @@ -1,40 +0,0 @@ -#pragma once - -#include <memory> -union SDL_Event; - -enum ModeSecondClick { Unset, Reset, NoAction }; - -template<typename Target, ModeSecondClick msc = ModeSecondClick::Unset> class Mode { -public: - explicit Mode(Target & t) : target {t} { } - - Target & target; - - template<typename Mode, typename... Params> - auto - toggle(Params &&... params) - { - return [params..., this](const SDL_Event &) { - toggleSetMode<Mode>(std::forward<Params>(params)...); - }; - } - -private: - template<typename Mode, typename... Params> - void - toggleSetMode(Params &&... params) - { - if (dynamic_cast<Mode *>(target.get())) { - if constexpr (msc == ModeSecondClick::Unset) { - target.reset(); - } - if constexpr (msc == ModeSecondClick::Reset) { - target = std::make_unique<Mode>(std::forward<Params>(params)...); - } - } - else { - target = std::make_unique<Mode>(std::forward<Params>(params)...); - } - } -}; diff --git a/ui/queryTool.cpp b/ui/queryTool.cpp new file mode 100644 index 0000000..549bd9e --- /dev/null +++ b/ui/queryTool.cpp @@ -0,0 +1,42 @@ +#include "queryTool.h" +#include "imgui_wrap.h" +#include <game/gamestate.h> +#include <game/selectable.h> +#include <game/terrain.h> +#include <game/worldobject.h> +#include <ray.h> +#include <stream_support.h> + +QueryTool::QueryTool() : clicked {"Click something for details"} { } + +bool +QueryTool::click(const SDL_MouseButtonEvent & event, const Ray<GlobalPosition3D> & ray) +{ + if (event.button != SDL_BUTTON_LEFT) { + return false; + } + BaryPosition baryPos {}; + RelativeDistance distance {}; + + if (const auto selected = gameState->world.applyOne<Selectable>(&Selectable::intersectRay, ray, baryPos, distance); + selected != gameState->world.end()) { + const auto & ref = *selected.base()->get(); + clicked = typeid(ref).name(); + } + else if (const auto pos = gameState->terrain->intersectRay(ray)) { + clicked = streamed_string(*pos); + } + else { + clicked.clear(); + } + return true; +} + +void +QueryTool::render(bool & open) +{ + ImGui::SetNextWindowSize({-1, -1}); + ImGui::Begin("Query Tool", &open); + ImGui::TextUnformatted(clicked.c_str()); + ImGui::End(); +} diff --git a/ui/queryTool.h b/ui/queryTool.h new file mode 100644 index 0000000..74c5380 --- /dev/null +++ b/ui/queryTool.h @@ -0,0 +1,17 @@ +#pragma once + +#include "gameMainSelector.h" + +class QueryTool : public GameMainSelector::Component { +public: + QueryTool(); + +protected: + using GameMainSelector::Component::render; + + bool click(const SDL_MouseButtonEvent &, const Ray<GlobalPosition3D> &) override; + void render(bool & open) override; + +private: + std::string clicked; +}; diff --git a/ui/svgIcon.cpp b/ui/svgIcon.cpp new file mode 100644 index 0000000..499d9cc --- /dev/null +++ b/ui/svgIcon.cpp @@ -0,0 +1,34 @@ +#include "svgIcon.h" +#include "gl_traits.h" +#include <resource.h> + +SvgIcon::SvgIcon(ImageDimensions dim, const std::filesystem::path & path) +{ + const auto svgDoc = lunasvg::Document::loadFromFile(Resource::mapPath(path).native()); + if (!svgDoc) { + throw std::runtime_error("Failed to load SVG from " + path.string()); + } + + auto bitmap = svgDoc->renderToBitmap(dim.x, dim.y); + if (bitmap.isNull()) { + throw std::runtime_error("Failed to render SVG " + path.string()); + } + bitmap.convertToRGBA(); + + glBindTexture(GL_TEXTURE_2D, texture); + + glTexParameter(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER); + glTexParameter(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER); + + glTexParameter(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameter(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, dim.x, dim.y, 0, GL_RGBA, GL_UNSIGNED_BYTE, bitmap.data()); +} + +ImTextureID +SvgIcon::operator*() const +{ + static_assert(sizeof(glTexture) <= sizeof(ImTextureID)); + // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast,performance-no-int-to-ptr) This is how ImGui works + return reinterpret_cast<ImTextureID>(*texture); +} diff --git a/ui/svgIcon.h b/ui/svgIcon.h new file mode 100644 index 0000000..106f97c --- /dev/null +++ b/ui/svgIcon.h @@ -0,0 +1,18 @@ +#pragma once + +#include "glArrays.h" +#include "imgui_wrap.h" +#include <config/types.h> +#include <filesystem> +#include <lunasvg.h> + +class SvgIcon { +public: + SvgIcon(ImageDimensions, const std::filesystem::path &); + + ImTextureID operator*() const; + +private: + friend class LoadFromFile; // Test case verifying size/content + glTexture texture; +}; diff --git a/ui/text.cpp b/ui/text.cpp deleted file mode 100644 index bdaaba5..0000000 --- a/ui/text.cpp +++ /dev/null @@ -1,73 +0,0 @@ -#include "text.h" -#include "font.h" -#include "gfx/gl/uiShader.h" -#include "gfx/gl/vertexArrayObject.h" -#include "uiComponent.h" -#include <array> -#include <collections.h> -#include <glArrays.h> -#include <glm/gtc/type_ptr.hpp> -#include <maths.h> -#include <numeric> -#include <utility> - -Text::Text(std::string_view s, const Font & font, Position pos, glm::vec3 c) : - UIComponent {pos}, colour {c}, font {font} -{ - VertexArrayObject {vao}.addAttribs<Font::Quad::value_type>(quads.bufferName(), 0); - operator=(s); -} - -Text & -Text::operator=(const std::string_view s) -{ - auto tquads = font.render(s); - models.resize(tquads.size()); - const auto glyphCount = std::accumulate(tquads.begin(), tquads.end(), size_t {}, [](auto && init, const auto & q) { - return init += q.second.size(); - }); - quads.resize(glyphCount); - GLushort current = 0; - auto model = models.begin(); - auto quad = quads.begin(); - for (const auto & [texture, fquads] : tquads) { - model->textureId = texture; - model->range.resize(fquads.size() * 6); - for (auto out = model->range.begin(); const auto & q [[maybe_unused]] : fquads) { - static constexpr std::array<GLushort, 6> quadIndices {0, 1, 2, 2, 3, 0}; - std::transform(quadIndices.begin(), quadIndices.end(), out, [current](auto x) { - return current + x; - }); - current += 4; - out += 6; - } - model++; - quad = std::transform(fquads.begin(), fquads.end(), quad, [this](const Font::Quad & q) { - return q * [this](const glm::vec4 & corner) { - return corner + glm::vec4 {this->position.origin, 0, 0}; - }; - }); - } - quads.unmap(); - return *this; -} - -void -Text::render(const UIShader & shader, const Position &) const -{ - shader.text.use(colour); - glActiveTexture(GL_TEXTURE0); - glBindVertexArray(vao); - for (const auto & m : models) { - glBindTexture(GL_TEXTURE_2D, m.textureId); - glDrawElements(GL_TRIANGLES, static_cast<GLsizei>(m.range.size()), GL_UNSIGNED_SHORT, m.range.data()); - } - glBindVertexArray(0); - glBindTexture(GL_TEXTURE_2D, 0); -} - -bool -Text::handleInput(const SDL_Event &, const Position &) -{ - return false; -} diff --git a/ui/text.h b/ui/text.h deleted file mode 100644 index a367456..0000000 --- a/ui/text.h +++ /dev/null @@ -1,34 +0,0 @@ -#pragma once - -#include "font.h" -#include "glContainer.h" -#include "uiComponent.h" -#include <glArrays.h> -#include <glad/gl.h> -#include <glm/glm.hpp> -#include <string_view> - -class UIShader; -union SDL_Event; - -class Text : public UIComponent { -public: - Text(std::string_view s, const Font &, Position, glm::vec3 colour); - - void render(const UIShader &, const Position & parentPos) const override; - bool handleInput(const SDL_Event &, const Position & parentPos) override; - - Text & operator=(const std::string_view s); - -private: - struct TextData { - GLuint textureId; - std::vector<unsigned short> range; - }; - - std::vector<TextData> models; - glContainer<Font::Quad> quads; - glVertexArray vao; - glm::vec3 colour; - const Font & font; -}; diff --git a/ui/toolbar.cpp b/ui/toolbar.cpp deleted file mode 100644 index 31d87dc..0000000 --- a/ui/toolbar.cpp +++ /dev/null @@ -1,35 +0,0 @@ -#include "toolbar.h" -#include "gfx/gl/uiShader.h" -#include "ui/iconButton.h" -#include "ui/uiComponent.h" -#include "uiComponentPlacer.h" -#include <SDL2/SDL.h> -#include <glm/glm.hpp> - -Toolbar::Toolbar(const std::initializer_list<InitInfo> & initInfo) : UIComponent {{{}, {}}} -{ - UIComponentPlacer placer {{10, 10}, 5, 1}; - for (const auto & ii : initInfo) { - icons.create(ii.first, placer.next(ICON_SIZE), ii.second); - } - this->position.size = placer.getLimit(); -} - -void -Toolbar::render(const UIShader & uiShader, const Position & parentPos) const -{ - uiShader.icon.use(); - const auto absPos = this->position + parentPos; - icons.apply(&UIComponent::render, uiShader, absPos); -} - -bool -Toolbar::handleInput(const SDL_Event & e, const Position & parentPos) -{ - const auto absPos = this->position + parentPos; - if (absPos & e.button) { - icons.applyOne(&UIComponent::handleInput, e, absPos); - return true; - } - return false; -} diff --git a/ui/toolbar.h b/ui/toolbar.h deleted file mode 100644 index ea560f5..0000000 --- a/ui/toolbar.h +++ /dev/null @@ -1,23 +0,0 @@ -#pragma once - -#include "collection.h" -#include "iconButton.h" -#include "uiComponent.h" -#include <initializer_list> -#include <string> -#include <utility> - -class UIShader; -union SDL_Event; - -class Toolbar : public UIComponent { -public: - using InitInfo = std::pair<std::string, UIEvent>; - explicit Toolbar(const std::initializer_list<InitInfo> & initInfo); - - void render(const UIShader & uiShader, const Position & parentPos) const override; - - bool handleInput(const SDL_Event & e, const Position & parentPos) override; - - Collection<IconButton, false> icons; -}; diff --git a/ui/uiComponent.cpp b/ui/uiComponent.cpp deleted file mode 100644 index aa4838d..0000000 --- a/ui/uiComponent.cpp +++ /dev/null @@ -1,33 +0,0 @@ -#include "uiComponent.h" -#include <SDL2/SDL.h> - -UIComponent::UIComponent(Position position) : position {position} { } - -UIComponent::Position -UIComponent::Position::operator+(const Position & parentPos) const -{ - return *this + parentPos.origin; -} - -UIComponent::Position -UIComponent::Position::operator+(const glm::vec2 & parentPos) const -{ - return {origin + parentPos, size}; -} - -bool -UIComponent::Position::operator&(const glm::vec2 & pos) const -{ - return (pos.x >= origin.x && pos.y >= origin.y && pos.x < origin.x + size.x && pos.y < origin.y + size.y); -} - -bool -UIComponent::Position::operator&(const SDL_MouseButtonEvent & pos) const -{ - switch (pos.type) { - case SDL_MOUSEBUTTONUP: - case SDL_MOUSEBUTTONDOWN: - return *this & glm::vec2 {pos.x, pos.y}; - } - return false; -} diff --git a/ui/uiComponent.h b/ui/uiComponent.h index 71d2659..b2c1a8f 100644 --- a/ui/uiComponent.h +++ b/ui/uiComponent.h @@ -1,32 +1,18 @@ #pragma once -#include <functional> #include <glm/glm.hpp> #include <special_members.h> -class UIShader; union SDL_Event; -struct SDL_MouseButtonEvent; -using UIEvent = std::function<void(const SDL_Event &)>; class UIComponent { public: - struct Position { - glm::vec2 origin, size; - Position operator+(const Position &) const; - Position operator+(const glm::vec2 &) const; - bool operator&(const SDL_MouseButtonEvent &) const; - bool operator&(const glm::vec2 &) const; - }; - - explicit UIComponent(Position); + UIComponent() = default; virtual ~UIComponent() = default; NO_MOVE(UIComponent); NO_COPY(UIComponent); - virtual void render(const UIShader &, const Position & parentPos) const = 0; - virtual bool handleInput(const SDL_Event &, const Position & parentPos) = 0; - - Position position; + virtual void render() = 0; + virtual bool handleInput(const SDL_Event &) = 0; }; diff --git a/ui/uiComponentPlacer.cpp b/ui/uiComponentPlacer.cpp deleted file mode 100644 index 5e645d8..0000000 --- a/ui/uiComponentPlacer.cpp +++ /dev/null @@ -1,27 +0,0 @@ -#include "uiComponentPlacer.h" -#include <algorithm> - -UIComponentPlacer::UIComponentPlacer(glm::vec2 padding, float spacing, glm::length_t axis) : - padding {padding}, spacing {spacing}, axis {axis}, current {padding[axis]} -{ -} - -glm::vec2 -UIComponentPlacer::next(glm::vec2 size) -{ - glm::vec2 n {}; - n[axis] = current; - n[1 - axis] = padding[1 - axis]; - current += spacing + size[axis]; - max = std::max(max, size[1 - axis]); - return n; -} - -glm::vec2 -UIComponentPlacer::getLimit() const -{ - glm::vec2 n {}; - n[axis] = current + padding[axis]; - n[1 - axis] = max + padding[1 - axis]; - return n; -} diff --git a/ui/uiComponentPlacer.h b/ui/uiComponentPlacer.h deleted file mode 100644 index 1e64f78..0000000 --- a/ui/uiComponentPlacer.h +++ /dev/null @@ -1,19 +0,0 @@ -#pragma once - -#include <glm/glm.hpp> - -class UIComponentPlacer { -public: - UIComponentPlacer(glm::vec2 padding, float spacing, glm::length_t axis = 0); - - glm::vec2 next(glm::vec2 size); - glm::vec2 getLimit() const; - -private: - const glm::vec2 padding; - const float spacing; - const glm::length_t axis; - - float current {}; - float max {}; -}; diff --git a/ui/windowContent.cpp b/ui/windowContent.cpp index 91732a7..0f6dc04 100644 --- a/ui/windowContent.cpp +++ b/ui/windowContent.cpp @@ -1,8 +1,6 @@ #include "windowContent.h" #include "SDL_events.h" -WindowContent::WindowContent(size_t width, size_t height) : uiShader {width, height} { } - void WindowContent::tick(TickDuration) { @@ -27,6 +25,6 @@ WindowContent::handleInput(const SDL_Event & e) eAdjusted.motion.y = size.y - e.motion.y; break; } - uiComponents.rapplyOne(&UIComponent::handleInput, eAdjusted, UIComponent::Position {{}, size}); + uiComponents.rapplyOne(&UIComponent::handleInput, eAdjusted); return true; } diff --git a/ui/windowContent.h b/ui/windowContent.h index 474445a..762d1cc 100644 --- a/ui/windowContent.h +++ b/ui/windowContent.h @@ -2,16 +2,13 @@ #include "chronology.h" #include "collection.h" -#include "gfx/gl/uiShader.h" #include "special_members.h" #include "stdTypeDefs.h" #include "uiComponent.h" // IWYU pragma: keep -#include <functional> class WindowContent : public StdTypeDefs<WindowContent> { public: - using Factory = std::function<Ptr(size_t width, size_t height)>; - WindowContent(size_t width, size_t height); + WindowContent() = default; virtual ~WindowContent() = default; NO_MOVE(WindowContent); NO_COPY(WindowContent); @@ -21,6 +18,5 @@ public: virtual bool handleInput(const SDL_Event & e); protected: - ::Collection<UIComponent> uiComponents; - UIShader uiShader; + UniqueCollection<UIComponent> uiComponents; }; |