summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitmodules3
-rw-r--r--Jamroot.jam1
-rw-r--r--config/types.h1
-rw-r--r--gfx/gl/shaders/uiShader.fs11
-rw-r--r--gfx/gl/shaders/uiShader.vs13
-rw-r--r--gfx/gl/shaders/uiShaderFont.fs12
-rw-r--r--gfx/gl/uiShader.cpp27
-rw-r--r--gfx/gl/uiShader.h47
-rw-r--r--lib/glArrays.h26
-rw-r--r--lib/jsonParse.ll9
-rw-r--r--res/ui/icon/magnifier.svg50
-rw-r--r--res/ui/icon/network.pngbin16793 -> 0 bytes
-rw-r--r--res/ui/icon/rails.svg36
-rw-r--r--res/ui/icon/road.svg27
-rw-r--r--test/Jamfile.jam26
-rw-r--r--test/test-lib.cpp4
-rw-r--r--test/test-text.cpp14
-rw-r--r--test/test-ui.cpp20
-rw-r--r--thirdparty/Jamfile.jam12
m---------thirdparty/imgui0
m---------thirdparty/lunasvg0
-rw-r--r--ui/editNetwork.cpp38
-rw-r--r--ui/editNetwork.h9
-rw-r--r--ui/gameMainSelector.cpp52
-rw-r--r--ui/gameMainSelector.h15
-rw-r--r--ui/gameMainWindow.cpp44
-rw-r--r--ui/icon.cpp9
-rw-r--r--ui/icon.h3
-rw-r--r--ui/iconButton.cpp57
-rw-r--r--ui/iconButton.h26
-rw-r--r--ui/imgui_extras.cpp33
-rw-r--r--ui/imgui_extras.h10
-rw-r--r--ui/imgui_wrap.h7
-rw-r--r--ui/manualCameraController.cpp4
-rw-r--r--ui/manualCameraController.h7
-rw-r--r--ui/modeHelper.h40
-rw-r--r--ui/queryTool.cpp42
-rw-r--r--ui/queryTool.h17
-rw-r--r--ui/svgIcon.cpp34
-rw-r--r--ui/svgIcon.h18
-rw-r--r--ui/text.cpp73
-rw-r--r--ui/text.h34
-rw-r--r--ui/toolbar.cpp35
-rw-r--r--ui/toolbar.h23
-rw-r--r--ui/uiComponent.cpp33
-rw-r--r--ui/uiComponent.h20
-rw-r--r--ui/uiComponentPlacer.cpp27
-rw-r--r--ui/uiComponentPlacer.h19
-rw-r--r--ui/windowContent.cpp4
-rw-r--r--ui/windowContent.h6
50 files changed, 446 insertions, 632 deletions
diff --git a/.gitmodules b/.gitmodules
index 63a1a38..b5aa2c7 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -7,3 +7,6 @@
[submodule "thirdparty/imgui"]
path = thirdparty/imgui
url = https://github.com/ocornut/imgui
+[submodule "thirdparty/lunasvg"]
+ path = thirdparty/lunasvg
+ url = https://github.com/sammycage/lunasvg
diff --git a/Jamroot.jam b/Jamroot.jam
index 8587aaa..9b589cf 100644
--- a/Jamroot.jam
+++ b/Jamroot.jam
@@ -92,7 +92,6 @@ lib ilt :
<library>thirdparty/<variant>release
<implicit-dependency>thirdparty
<library>sdl2
- <library>thirdparty//imguisdl2
<library>freetype2
<library>glib-2.0
<library>mxml
diff --git a/config/types.h b/config/types.h
index c501f41..06825b5 100644
--- a/config/types.h
+++ b/config/types.h
@@ -42,6 +42,7 @@ using Normal3D = Normal<3>;
using Rotation2D = Rotation<2>;
using Rotation3D = Rotation<3>;
using TextureRelCoord = glm::vec<2, float>;
+using ImageDimensions = glm::vec<2, GLsizei>;
using TextureDimensions = glm::vec<3, GLsizei>;
using TextureRelRegion = glm::vec<4, float>;
using TextureAbsCoord = glm::vec<2, GLsizei>;
diff --git a/gfx/gl/shaders/uiShader.fs b/gfx/gl/shaders/uiShader.fs
deleted file mode 100644
index c5f4e92..0000000
--- a/gfx/gl/shaders/uiShader.fs
+++ /dev/null
@@ -1,11 +0,0 @@
-#version 330 core
-
-in vec2 texCoord0;
-
-uniform sampler2D sampler;
-
-void
-main()
-{
- gl_FragColor = texture(sampler, texCoord0);
-}
diff --git a/gfx/gl/shaders/uiShader.vs b/gfx/gl/shaders/uiShader.vs
deleted file mode 100644
index e9e4373..0000000
--- a/gfx/gl/shaders/uiShader.vs
+++ /dev/null
@@ -1,13 +0,0 @@
-#version 330 core
-
-in vec4 position;
-
-out vec2 texCoord0;
-uniform mat4 uiProjection;
-
-void
-main()
-{
- gl_Position = uiProjection * vec4(position.xy, 0.0, 1.0);
- texCoord0 = position.zw;
-}
diff --git a/gfx/gl/shaders/uiShaderFont.fs b/gfx/gl/shaders/uiShaderFont.fs
deleted file mode 100644
index a1ef6ef..0000000
--- a/gfx/gl/shaders/uiShaderFont.fs
+++ /dev/null
@@ -1,12 +0,0 @@
-#version 330 core
-
-in vec2 texCoord0;
-
-uniform sampler2D sampler;
-uniform vec3 colour;
-
-void
-main()
-{
- gl_FragColor = vec4(colour, texture(sampler, texCoord0).r);
-}
diff --git a/gfx/gl/uiShader.cpp b/gfx/gl/uiShader.cpp
deleted file mode 100644
index 23da9dc..0000000
--- a/gfx/gl/uiShader.cpp
+++ /dev/null
@@ -1,27 +0,0 @@
-#include "uiShader.h"
-#include "gl_traits.h"
-#include <gfx/gl/program.h>
-#include <gfx/gl/shader.h>
-#include <gfx/gl/shaders/fs-uiShader.h>
-#include <gfx/gl/shaders/fs-uiShaderFont.h>
-#include <gfx/gl/shaders/vs-uiShader.h>
-#include <glm/glm.hpp>
-#include <glm/gtc/type_ptr.hpp>
-
-UIShader::IconProgram::IconProgram(const glm::mat4 & vp) : UIProgram {vp, uiShader_vs, uiShader_fs} { }
-
-UIShader::TextProgram::TextProgram(const glm::mat4 & vp) : UIProgram {vp, uiShader_vs, uiShaderFont_fs} { }
-
-UIShader::UIShader(size_t width, size_t height) :
- UIShader {glm::ortho<float>(0, static_cast<float>(width), 0, static_cast<float>(height))}
-{
-}
-
-UIShader::UIShader(const glm::mat4 & viewProjection) : icon {viewProjection}, text {viewProjection} { }
-
-void
-UIShader::TextProgram::use(const RGB & colour) const
-{
- Program::use();
- glUniform(colorLoc, colour);
-}
diff --git a/gfx/gl/uiShader.h b/gfx/gl/uiShader.h
deleted file mode 100644
index 6d00166..0000000
--- a/gfx/gl/uiShader.h
+++ /dev/null
@@ -1,47 +0,0 @@
-#pragma once
-
-#include "config/types.h"
-#include "gl_traits.h"
-#include "program.h"
-#include <cstddef>
-#include <glad/gl.h>
-#include <glm/glm.hpp>
-#include <glm/gtc/type_ptr.hpp>
-
-class UIShader {
-public:
- UIShader(std::size_t width, std::size_t height);
-
-private:
- explicit UIShader(const glm::mat4 & viewProjection);
-
- class UIProgram : public Program {
- public:
- template<typename... S>
- explicit UIProgram(const glm::mat4 & vp, S &&... srcs) : Program {std::forward<S>(srcs)...}
- {
- const RequiredUniformLocation uiProjectionLoc {*this, "uiProjection"};
- glUseProgram(*this);
- glUniform(uiProjectionLoc, vp);
- }
- };
-
- class IconProgram : public UIProgram {
- public:
- explicit IconProgram(const glm::mat4 & vp);
- using Program::use;
- };
-
- class TextProgram : public UIProgram {
- public:
- explicit TextProgram(const glm::mat4 & vp);
- void use(const RGB & colour) const;
-
- private:
- RequiredUniformLocation colorLoc {*this, "colour"};
- };
-
-public:
- IconProgram icon;
- TextProgram text;
-};
diff --git a/lib/glArrays.h b/lib/glArrays.h
index 787ea17..842a593 100644
--- a/lib/glArrays.h
+++ b/lib/glArrays.h
@@ -6,6 +6,7 @@
#include <glad/gl.h>
#include <special_members.h>
+// NOLINTNEXTLINE(readability-identifier-naming)
template<size_t N> class glArraysBase {
static_assert(N > 0);
@@ -15,20 +16,30 @@ public:
CUSTOM_MOVE(glArraysBase);
// NOLINTNEXTLINE(hicpp-explicit-conversions)
- inline
operator GLuint() const
+ requires(N == 1)
{
- static_assert(N == 1, "Implicit cast only if N == 1");
return ids.front();
}
- inline auto
+ GLuint
+ operator*() const
+ requires(N == 1)
+ {
+ return ids.front();
+ }
+
+ const auto &
operator[](size_t n) const
{
return ids[n];
}
- constexpr static auto size {N};
+ constexpr static auto
+ size()
+ {
+ return N;
+ }
protected:
glArraysBase() noexcept = default;
@@ -49,6 +60,7 @@ glArraysBase<N>::operator=(glArraysBase<N> && src) noexcept
return *this;
}
+// NOLINTNEXTLINE(readability-identifier-naming)
template<size_t N, auto Gen, auto Del> class glArrays : public glArraysBase<N> {
public:
using glArraysBase<N>::glArraysBase;
@@ -56,12 +68,12 @@ public:
DEFAULT_MOVE_COPY(glArrays);
- inline glArrays() noexcept
+ glArrays() noexcept
{
(*Gen)(N, this->ids.data());
}
- inline ~glArrays() noexcept
+ ~glArrays() noexcept
{
if (this->ids.front()) {
(*Del)(N, this->ids.data());
@@ -69,6 +81,7 @@ public:
}
};
+// NOLINTBEGIN(readability-identifier-naming)
template<size_t N> using glVertexArrays = glArrays<N, &glGenVertexArrays, &glDeleteVertexArrays>;
using glVertexArray = glVertexArrays<1>;
template<size_t N> using glBuffers = glArrays<N, &glGenBuffers, &glDeleteBuffers>;
@@ -79,3 +92,4 @@ template<size_t N> using glFrameBuffers = glArrays<N, &glGenFramebuffers, &glDel
using glFrameBuffer = glFrameBuffers<1>;
template<size_t N> using glRenderBuffers = glArrays<N, &glGenRenderbuffers, &glDeleteRenderbuffers>;
using glRenderBuffer = glRenderBuffers<1>;
+// NOLINTEND(readability-identifier-naming)
diff --git a/lib/jsonParse.ll b/lib/jsonParse.ll
index 100bc46..abcd070 100644
--- a/lib/jsonParse.ll
+++ b/lib/jsonParse.ll
@@ -149,7 +149,10 @@ text [^\\\"]*
<*>. {
LexerError("Unexpected input");
- // Make iwyu think unistd.h is required
- [[maybe_unused]]static constexpr auto x=getpid;
- [[maybe_unused]]static constexpr auto y=printf;
}
+
+%%
+
+// Make iwyu think unistd.h is required
+[[maybe_unused]]static constexpr auto x=getpid;
+[[maybe_unused]]static constexpr auto y=printf;
diff --git a/res/ui/icon/magnifier.svg b/res/ui/icon/magnifier.svg
new file mode 100644
index 0000000..97abe9f
--- /dev/null
+++ b/res/ui/icon/magnifier.svg
@@ -0,0 +1,50 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<!-- Creator: CorelDRAW -->
+<svg xmlns="http://www.w3.org/2000/svg" xml:space="preserve" width="1.70666in" height="1.70666in" version="1.1" style="shape-rendering:geometricPrecision; text-rendering:geometricPrecision; image-rendering:optimizeQuality; fill-rule:evenodd; clip-rule:evenodd"
+viewBox="0 0 1707 1707"
+ xmlns:xlink="http://www.w3.org/1999/xlink">
+ <defs>
+ <style type="text/css">
+ <![CDATA[
+ .fil3 {fill:url(#id0)}
+ .fil0 {fill:url(#id1)}
+ .fil2 {fill:url(#id2)}
+ .fil4 {fill:url(#id3)}
+ .fil1 {fill:url(#id4)}
+ .fil5 {fill:url(#id5)}
+ ]]>
+ </style>
+ <linearGradient id="id0" gradientUnits="userSpaceOnUse" x1="647.772" y1="1185.78" x2="647.772" y2="109.768">
+ <stop offset="0" style="stop-opacity:1; stop-color:#AFAFAF"/>
+ <stop offset="1" style="stop-opacity:1; stop-color:#9C9C9C"/>
+ </linearGradient>
+ <linearGradient id="id1" gradientUnits="userSpaceOnUse" x1="1138.83" y1="1294.33" x2="1138.83" y2="983.327">
+ <stop offset="0" style="stop-opacity:1; stop-color:#949494"/>
+ <stop offset="1" style="stop-opacity:1; stop-color:#858585"/>
+ </linearGradient>
+ <linearGradient id="id2" gradientUnits="userSpaceOnUse" xlink:href="#id1" x1="647.772" y1="1295.55" x2="647.772" y2="0.00393701">
+ </linearGradient>
+ <linearGradient id="id3" gradientUnits="userSpaceOnUse" x1="647.772" y1="1143.81" x2="647.772" y2="151.736">
+ <stop offset="0" style="stop-opacity:1; stop-color:#D2D2D2"/>
+ <stop offset="1" style="stop-opacity:1; stop-color:#BBBBBB"/>
+ </linearGradient>
+ <linearGradient id="id4" gradientUnits="userSpaceOnUse" x1="1411.49" y1="1116.31" x2="1411.49" y2="1706.66">
+ <stop offset="0" style="stop-opacity:1; stop-color:#FF9911"/>
+ <stop offset="1" style="stop-opacity:1; stop-color:#FF6600"/>
+ </linearGradient>
+ <linearGradient id="id5" gradientUnits="userSpaceOnUse" x1="657.22" y1="496.535" x2="657.22" y2="322.63">
+ <stop offset="0" style="stop-opacity:1; stop-color:#E6E6E6"/>
+ <stop offset="1" style="stop-opacity:1; stop-color:#CCCCCC"/>
+ </linearGradient>
+ </defs>
+ <g id="Layer_x0020_1">
+ <metadata id="CorelCorpID_0Corel-Layer"/>
+ <path class="fil0" d="M1161 983l133 133 -178 178 -133 -133c36,-21 69,-47 100,-78 31,-31 57,-64 78,-100z"/>
+ <path class="fil1" d="M1116 1294l178 -178 376 376c49,49 49,129 0,178l0 0c-49,49 -129,49 -178,0l-376 -376z"/>
+ <path class="fil2" d="M190 190c253,-253 663,-253 916,0 253,253 253,663 0,916 -253,253 -663,253 -916,0 -253,-253 -253,-663 0,-916z"/>
+ <path class="fil3" d="M267 267c210,-210 551,-210 761,0 210,210 210,551 0,761 -210,210 -551,210 -761,0 -210,-210 -210,-551 0,-761z"/>
+ <path class="fil4" d="M297 297c194,-194 508,-194 702,0 193,194 193,508 0,702 -194,193 -508,193 -702,0 -194,-194 -194,-508 0,-702z"/>
+ <path class="fil5" d="M440 486c-14,14 -37,14 -52,0 -14,-15 -14,-38 0,-52 75,-74 172,-111 269,-111 97,0 195,37 269,111 14,14 14,38 0,52 -14,14 -37,14 -52,0 -60,-60 -138,-90 -217,-90 -79,0 -157,30 -217,90z"/>
+ </g>
+</svg>
diff --git a/res/ui/icon/network.png b/res/ui/icon/network.png
deleted file mode 100644
index 7a091f3..0000000
--- a/res/ui/icon/network.png
+++ /dev/null
Binary files differ
diff --git a/res/ui/icon/rails.svg b/res/ui/icon/rails.svg
new file mode 100644
index 0000000..81e9b94
--- /dev/null
+++ b/res/ui/icon/rails.svg
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<!-- Creator: CorelDRAW -->
+<svg xmlns="http://www.w3.org/2000/svg" xml:space="preserve" width="1.99999in" height="1.99999in" version="1.1" style="shape-rendering:geometricPrecision; text-rendering:geometricPrecision; image-rendering:optimizeQuality; fill-rule:evenodd; clip-rule:evenodd"
+viewBox="0 0 2000 2000"
+ xmlns:xlink="http://www.w3.org/1999/xlink">
+ <defs>
+ <style type="text/css">
+ <![CDATA[
+ .fil0 {fill:none}
+ .fil1 {fill:#333333}
+ .fil2 {fill:#C06000}
+ .fil3 {fill:#CCCCCC}
+ ]]>
+ </style>
+ </defs>
+ <rect class="fil0" width="2000" height="2000"/>
+ <g id="Layer_x0020_1">
+ <metadata id="CorelCorpID_0Corel-Layer"/>
+ <path class="fil1" d="M1448 515l-61 0 29 126 108 0c30,0 55,23 63,59l38 168c8,37 -28,69 -63,69l-80 0 28 126 127 0c31,0 55,23 63,59l38 168c9,37 -27,69 -63,69l-98 0 28 126 146 0c31,0 55,22 63,58l38 169c8,37 -27,68 -63,68l-126 0c-8,20 -30,34 -51,34l-81 0c-21,0 -38,-13 -48,-34l-966 0c-10,21 -27,34 -48,34l-81 0c-21,0 -43,-14 -51,-34l-126 0c-36,0 -71,-31 -63,-68l38 -169c8,-36 32,-58 63,-58l146 0 29 -126 -99 0c-36,0 -72,-32 -63,-69l38 -168c8,-36 32,-59 63,-59l127 0 28 -126 -80 0c-35,0 -71,-32 -63,-69l38 -168c8,-36 32,-59 63,-59l109 0 28 -126c-40,0 -87,8 -113,-25 -10,-13 -14,-28 -11,-44 56,-248 29,-226 192,-226 10,-21 27,-34 49,-34l80 0c21,0 43,14 51,34l278 0c8,-20 30,-34 51,-34l81 0c21,0 39,13 48,34 163,0 136,-21 192,226 8,37 -28,69 -63,69zm-971 1239l341 -1516 0 -1c-1,-2 -5,-4 -8,-4l-80 0c-5,0 -8,10 -9,15l-338 1506c-2,7 -5,13 5,13l81 0c4,0 7,-8 8,-13zm108 -269l830 0 -28 -126 -773 0 -29 126zm95 -422l640 0 -28 -126 -584 0 -28 126zm95 -422l450 0 -28 -126 -394 0 -28 126zm-436 1093l46 -202 -136 0 0 0c-12,0 -16,17 -18,22l-37 168c-2,6 12,12 17,12l128 0zm95 -422l45 -202 -116 0 0 0c-12,0 -17,17 -18,22l-38 168c-1,7 13,12 18,12l109 0zm425 -1046l-45 202 373 0 -46 -202 -282 0zm-95 422l-45 202 562 0 -45 -202 -472 0zm-94 422l-46 202 752 0 -45 -202 -661 0zm-95 422l-46 202 942 0 -46 -202 -850 0zm760 -1035l-56 -251c-1,-5 -4,-13 -9,-13l-80 0c-3,0 -6,2 -8,4l341 1517c1,5 5,13 8,13l81 0c3,0 7,-2 8,-4l-285 -1266zm-4 -231l46 202 71 0c5,0 19,-5 17,-11l-37 -169c-2,-5 -6,-22 -18,-22l-79 0zm95 422l45 202 91 0c4,0 19,-5 17,-12l-38 -168c-1,-5 -6,-22 -17,-22l-98 0zm95 422l45 202 109 0c6,0 19,-5 18,-12l-38 -168c-1,-5 -6,-22 -17,-22l-117 0zm95 422l45 202 128 0c6,0 18,-6 18,-12l-38 -168c-1,-5 -6,-22 -18,-22l-135 0zm-1140 -844c-11,0 -16,17 -17,22l-38 168c-2,7 13,12 17,12l91 0 45 -202 -98 0zm114 -422c-12,0 -16,17 -17,22l-38 169c-2,6 12,11 17,11l72 0 45 -202 -79 0z"/>
+ <path class="fil2" d="M339 1734l46 -202 -136 0 0 0c-12,0 -16,17 -18,22l-37 168c-2,6 12,12 17,12l128 0z"/>
+ <path class="fil3" d="M721 248l-338 1506c-2,7 -5,13 5,13l81 0c4,0 7,-8 8,-13l341 -1516 0 -1c-1,-2 -5,-4 -8,-4l-80 0c-5,0 -8,10 -9,15z"/>
+ <polygon class="fil2" points="1425,1532 575,1532 529,1734 1471,1734 "/>
+ <path class="fil3" d="M1182 237l341 1517c1,5 5,13 8,13l81 0c3,0 7,-2 8,-4l-285 -1266 -56 -251c-1,-5 -4,-13 -9,-13l-80 0c-3,0 -6,2 -8,4z"/>
+ <path class="fil2" d="M1751 1532l-135 0 45 202 128 0c6,0 18,-6 18,-12l-38 -168c-1,-5 -6,-22 -18,-22z"/>
+ <path class="fil2" d="M1566 1312l109 0c6,0 19,-5 18,-12l-38 -168c-1,-5 -6,-22 -17,-22l-117 0 45 202z"/>
+ <polygon class="fil2" points="1376,1312 1331,1110 670,1110 624,1312 "/>
+ <path class="fil2" d="M434 1312l45 -202 -116 0 0 0c-12,0 -17,17 -18,22l-38 168c-1,7 13,12 18,12l109 0z"/>
+ <path class="fil2" d="M438 890l91 0 45 -202 -98 0c-11,0 -16,17 -17,22l-38 168c-2,7 13,12 17,12z"/>
+ <polygon class="fil2" points="764,688 719,890 1281,890 1236,688 "/>
+ <path class="fil2" d="M1426 688l45 202 91 0c4,0 19,-5 17,-12l-38 -168c-1,-5 -6,-22 -17,-22l-98 0z"/>
+ <path class="fil2" d="M1377 468l71 0c5,0 19,-5 17,-11l-37 -169c-2,-5 -6,-22 -18,-22l-79 0 46 202z"/>
+ <polygon class="fil2" points="1187,468 1141,266 859,266 814,468 "/>
+ <path class="fil2" d="M624 468l45 -202 -79 0c-12,0 -16,17 -17,22l-38 169c-2,6 12,11 17,11l72 0z"/>
+ </g>
+</svg>
diff --git a/res/ui/icon/road.svg b/res/ui/icon/road.svg
new file mode 100644
index 0000000..3b9ae77
--- /dev/null
+++ b/res/ui/icon/road.svg
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<!-- Creator: CorelDRAW -->
+<svg xmlns="http://www.w3.org/2000/svg" xml:space="preserve" width="512px" height="512px" version="1.1" style="shape-rendering:geometricPrecision; text-rendering:geometricPrecision; image-rendering:optimizeQuality; fill-rule:evenodd; clip-rule:evenodd"
+viewBox="0 0 512 512"
+ xmlns:xlink="http://www.w3.org/1999/xlink">
+ <defs>
+ <style type="text/css">
+ <![CDATA[
+ .fil0 {fill:#4D4D4D}
+ .fil1 {fill:#99A4AC}
+ .fil2 {fill:#D9F2F2}
+ ]]>
+ </style>
+ </defs>
+ <g id="Layer_x0020_1">
+ <metadata id="CorelCorpID_0Corel-Layer"/>
+ <path class="fil0" d="M491 512l-470 0c-5,0 -8,-4 -7,-8l82 -498c1,-3 4,-6 8,-6l308 0c4,0 7,2 7,6l79 498c1,3 -2,8 -7,8zm-406 -14l56 -484 -31 0 -81 484 56 0zm288 -484l54 484 56 0 -77 -484 -33 0zm40 484l-54 -484 -64 0 0 86c-1,4 -4,7 -8,7l-47 0c-4,0 -7,-3 -7,-7l0 -86 -77 0 -57 484 134 0 0 -86c0,-4 3,-8 7,-8l47 0c4,0 8,4 8,8l0 86 118 0zm-133 0l0 -79 -33 0 0 79 33 0zm7 -121l-47 0c-4,0 -7,-3 -7,-7l0 -93c0,-4 3,-8 7,-8l47 0c4,0 8,4 8,8l0 93c-1,4 -4,7 -8,7zm-40 -14l33 0 0 -79 -33 0 0 79zm40 -121l-47 0c-4,0 -7,-3 -7,-7l0 -93c0,-4 3,-8 7,-8l47 0c4,0 8,4 8,8l0 93c-1,4 -4,7 -8,7zm-40 -14l33 0 0 -79 -33 0 0 79zm0 -135l33 0 0 -79 -33 0 0 79z"/>
+ <path class="fil1" d="M295 498l118 0 -54 -484 -64 0 0 86c-1,4 -4,7 -8,7l-47 0c-4,0 -7,-3 -7,-7l0 -86 -77 0 -57 484 134 0 0 -86c0,-4 3,-8 7,-8l47 0c4,0 8,4 8,8l0 86zm0 -221l0 93c-1,4 -4,7 -8,7l-47 0c-4,0 -7,-3 -7,-7l0 -93c0,-4 3,-8 7,-8l47 0c4,0 8,4 8,8zm-8 -35l-47 0c-4,0 -7,-3 -7,-7l0 -93c0,-4 3,-8 7,-8l47 0c4,0 8,4 8,8l0 93c-1,4 -4,7 -8,7z"/>
+ <polygon class="fil2" points="247,228 280,228 280,149 247,149 "/>
+ <polygon class="fil2" points="280,284 247,284 247,363 280,363 "/>
+ <polygon class="fil2" points="280,419 247,419 247,498 280,498 "/>
+ <polygon class="fil2" points="247,93 280,93 280,14 247,14 "/>
+ <polygon class="fil1" points="373,14 427,498 483,498 406,14 "/>
+ <polygon class="fil1" points="85,498 141,14 110,14 29,498 "/>
+ </g>
+</svg>
diff --git a/test/Jamfile.jam b/test/Jamfile.jam
index bedc2ad..bdaaa45 100644
--- a/test/Jamfile.jam
+++ b/test/Jamfile.jam
@@ -43,6 +43,16 @@ project : requirements
<toolset>tidy:<librarydef>boost
;
lib test : [ glob *.cpp : test-*.cpp perf-*.cpp ] ;
+rule perfrun ( main + : extra-requirements * : runtime-dependency * : command-args * ) {
+ local name = $(main[0]:S=) ;
+ local benchmark = $(main[0]:S=.benchmark) ;
+ explicit $(name) ;
+ exe $(benchmark) : $(main) :
+ <library>benchmark
+ <library>test
+ $(extra-requirements) ;
+ run $(benchmark) : $(command-args) : : <dependency>$(runtime-dependency) : $(name) ;
+}
run test-collection.cpp ;
run test-maths.cpp ;
@@ -55,22 +65,18 @@ run test-enumDetails.cpp ;
run test-render.cpp : -- : test-assetFactory : <library>test ;
run test-glContextBhvr.cpp ;
run test-assetFactory.cpp : -- : [ sequence.insertion-sort [ glob-tree $(res) : *.* ] fixtures/rgb.txt test-instancing ] : <library>test ;
-run perf-assetFactory.cpp : \< : test-assetFactory : <library>benchmark <library>test ;
-run perf-geoData.cpp : \< : test-geoData : <library>test <library>benchmark ;
-run perf-terrain.cpp : \< : test-geoData : <library>test <library>benchmark ;
-run perf-persistence.cpp : \< : test-persistence : <library>benchmark <library>test ;
+perfrun perf-assetFactory.cpp : : test-assetFactory ;
+perfrun perf-geoData.cpp : : test-geoData ;
+perfrun perf-terrain.cpp : : test-geoData ;
+perfrun perf-persistence.cpp : : test-persistence ;
run test-worker.cpp ;
run test-instancing.cpp : -- : test-glContainer : <library>test ;
-run perf-instancing.cpp : \< : test-instancing : <library>benchmark <library>test ;
+perfrun perf-instancing.cpp : : test-instancing ;
run test-glContainer.cpp : : : <library>test ;
run test-pack.cpp : : : <library>test ;
run test-environment.cpp : : : <library>test ;
+run test-ui.cpp : : : <library>test ;
compile test-static-enumDetails.cpp ;
compile test-static-stream_support.cpp ;
-explicit perf-assetFactory ;
-explicit perf-persistence ;
-explicit perf-geoData ;
-explicit perf-instancing ;
-explicit perf-terrain ;
alias perf : perf-assetFactory perf-persistence perf-geoData perf-instancing perf-terrain ;
explicit perf ;
diff --git a/test/test-lib.cpp b/test/test-lib.cpp
index ec91f6e..a1a8c80 100644
--- a/test/test-lib.cpp
+++ b/test/test-lib.cpp
@@ -46,9 +46,9 @@ BOOST_AUTO_TEST_CASE(generate_move_and_delete)
{
{
TestArray a;
- BOOST_CHECK_EQUAL(TestArray::size, active.size());
+ BOOST_CHECK_EQUAL(TestArray::size(), active.size());
const TestArray b {std::move(a)};
- BOOST_CHECK_EQUAL(TestArray::size, active.size());
+ BOOST_CHECK_EQUAL(TestArray::size(), active.size());
}
BOOST_CHECK(active.empty());
}
diff --git a/test/test-text.cpp b/test/test-text.cpp
index b0a9503..0729ce8 100644
--- a/test/test-text.cpp
+++ b/test/test-text.cpp
@@ -7,7 +7,6 @@
#include "testMainWindow.h"
#include "testRenderOutput.h"
-#include "ui/text.h"
#include <array>
#include <gfx/models/texture.h>
#include <glm/glm.hpp>
@@ -112,19 +111,6 @@ BOOST_AUTO_TEST_CASE(render_font)
}
}
-BOOST_AUTO_TEST_CASE(render_text)
-{
- TestRenderOutput output;
- glBindFramebuffer(GL_FRAMEBUFFER, output.output);
- glViewport(0, 0, 640, 480);
- glEnable(GL_BLEND);
- glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
- Text t {"I Like Trains", *this, {{10, 10}, {200, 40}}, {1, 1, 1}};
- UIShader s {640, 480};
- t.render(s, {});
- Texture::save(output.outImage, "/tmp/text.tga");
-}
-
BOOST_AUTO_TEST_SUITE_END()
BOOST_AUTO_TEST_CASE(stream_vec)
diff --git a/test/test-ui.cpp b/test/test-ui.cpp
new file mode 100644
index 0000000..2810cda
--- /dev/null
+++ b/test/test-ui.cpp
@@ -0,0 +1,20 @@
+#define BOOST_TEST_MODULE UI
+#include <boost/test/unit_test.hpp>
+#include <stream_support.h>
+
+#include "testMainWindow.h"
+#include <gfx/models/texture.h>
+#include <resource.h>
+#include <ui/svgIcon.h>
+
+constexpr GLsizei RENDER_SIZE = 64;
+
+BOOST_GLOBAL_FIXTURE(TestMainWindowAppBase);
+
+BOOST_AUTO_TEST_CASE(LoadFromFile)
+{
+ SvgIcon svg(ImageDimensions {RENDER_SIZE}, Resource::mapPath("ui/icon/rails.svg"));
+ const auto size = Texture::getSize(svg.texture);
+ BOOST_CHECK_EQUAL(size, TextureDimensions(RENDER_SIZE, RENDER_SIZE, 1));
+ Texture::save(svg.texture, "/tmp/rails.tga");
+}
diff --git a/thirdparty/Jamfile.jam b/thirdparty/Jamfile.jam
index b6ed163..26497c9 100644
--- a/thirdparty/Jamfile.jam
+++ b/thirdparty/Jamfile.jam
@@ -28,3 +28,15 @@ lib imguisdl2 :
: :
<include>imgui
;
+
+lib lunasvg :
+ [ glob lunasvg/source/*.cpp lunasvg/plutovg/source/*.c ]
+ :
+ <link>static
+ <include>lunasvg/include
+ <include>lunasvg/plutovg/include
+ <warnings>off
+ <cflags>-fPIC
+ : :
+ <include>lunasvg/include
+ ;
diff --git a/thirdparty/imgui b/thirdparty/imgui
-Subproject 2db79d0868f7b02d26f7557a72504a0b6f84493
+Subproject b4c96355c9b51b54c4deb52e7d7cdfc7bf79bc2
diff --git a/thirdparty/lunasvg b/thirdparty/lunasvg
new file mode 160000
+Subproject f8aabfb444bb37f69df7290790f57e4a27730a9
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 2fc102a..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>;
@@ -42,10 +40,7 @@ public:
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 f8c568b..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,21 +17,43 @@
#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});
+ auto gms = uiComponents.create<GameMainSelector>(&camera);
uiComponents.create<GameMainToolbar>(gms);
}
@@ -69,7 +91,7 @@ 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
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);
}
diff --git a/ui/icon.h b/ui/icon.h
index 76cd3ae..3d0788a 100644
--- a/ui/icon.h
+++ b/ui/icon.h
@@ -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/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 b0480e2..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;
-
- UniqueCollection<IconButton> 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 5437da6..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);
@@ -22,5 +19,4 @@ public:
protected:
UniqueCollection<UIComponent> uiComponents;
- UIShader uiShader;
};