diff options
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 Binary files differdeleted file mode 100644 index 7a091f3..0000000 --- a/res/ui/icon/network.png +++ /dev/null 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); } @@ -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; }; |