summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDan Goodliffe <dan@randomdan.homeip.net>2022-01-01 13:01:08 +0000
committerDan Goodliffe <dan@randomdan.homeip.net>2022-01-01 14:40:06 +0000
commit1f68fe78e84f25c8ddacdc37a293a5de31725bab (patch)
tree4537db483391b579387c1bcc00c3f1e3b6adc106
parentAdd glm::vec concatenation operator|| (diff)
downloadilt-1f68fe78e84f25c8ddacdc37a293a5de31725bab.tar.bz2
ilt-1f68fe78e84f25c8ddacdc37a293a5de31725bab.tar.xz
ilt-1f68fe78e84f25c8ddacdc37a293a5de31725bab.zip
First iteration with font/text support
-rw-r--r--Jamroot.jam5
-rw-r--r--gfx/gl/shaders/uiShaderFont.fs12
-rw-r--r--gfx/gl/uiShader.cpp30
-rw-r--r--gfx/gl/uiShader.h6
-rw-r--r--iwyu.json16
-rw-r--r--lib/unicode.c13
-rw-r--r--lib/unicode.h20
-rw-r--r--test/Jamfile.jam1
-rw-r--r--test/test-text.cpp91
-rw-r--r--ui/font.cpp182
-rw-r--r--ui/font.h48
-rw-r--r--ui/text.cpp59
-rw-r--r--ui/text.h31
-rw-r--r--ui/toolbar.cpp2
-rw-r--r--ui/window.cpp2
15 files changed, 508 insertions, 10 deletions
diff --git a/Jamroot.jam b/Jamroot.jam
index ce4b342..d4476e3 100644
--- a/Jamroot.jam
+++ b/Jamroot.jam
@@ -10,6 +10,8 @@ import sequence ;
pkg-config.import sdl2 ;
pkg-config.import glew ;
+pkg-config.import freetype2 ;
+pkg-config.import glib-2.0 ;
lib pthread ;
variant coverage : debug ;
@@ -72,6 +74,7 @@ lib ilt :
<include>.
<include>lib
<link>static
+ <use>glib-2.0
<cflags>-fPIC
]
:
@@ -96,6 +99,8 @@ lib ilt :
<include>lib
<library>sdl2
<library>glew
+ <library>freetype2
+ <library>glib-2.0
<library>pthread
: :
<include>.
diff --git a/gfx/gl/shaders/uiShaderFont.fs b/gfx/gl/shaders/uiShaderFont.fs
new file mode 100644
index 0000000..bee455d
--- /dev/null
+++ b/gfx/gl/shaders/uiShaderFont.fs
@@ -0,0 +1,12 @@
+#version 130
+
+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
index 1c2a0e1..fbcdd15 100644
--- a/gfx/gl/uiShader.cpp
+++ b/gfx/gl/uiShader.cpp
@@ -2,20 +2,36 @@
#include <gfx/gl/glSource.h>
#include <gfx/gl/programHandle.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>
+#include <initializer_list>
-UIShader::UIShader(size_t width, size_t height) : program {uiShader_vs.compile(), uiShader_fs.compile()}
+UIShader::UIShader(size_t width, size_t height) :
+ progDefault {uiShader_vs.compile(), uiShader_fs.compile()}, progText {uiShader_vs.compile(),
+ uiShaderFont_fs.compile()}
{
- if (auto loc = glGetUniformLocation(program.m_program, "uiProjection"); loc >= 0) {
- glUseProgram(program.m_program);
- const auto uiProjection = glm::ortho<float>(0, static_cast<float>(width), 0, static_cast<float>(height));
- glUniformMatrix4fv(loc, 1, GL_FALSE, glm::value_ptr(uiProjection));
+ for (const auto prog : {&progDefault, &progText}) {
+ if (auto loc = glGetUniformLocation(prog->m_program, "uiProjection"); loc >= 0) {
+ glUseProgram(prog->m_program);
+ const auto uiProjection = glm::ortho<float>(0, static_cast<float>(width), 0, static_cast<float>(height));
+ glUniformMatrix4fv(loc, 1, GL_FALSE, glm::value_ptr(uiProjection));
+ }
}
}
+
+void
+UIShader::useDefault() const
+{
+ glUseProgram(progDefault.m_program);
+}
+
void
-UIShader::use() const
+UIShader::useText(glm::vec3 colour) const
{
- glUseProgram(program.m_program);
+ glUseProgram(progText.m_program);
+ if (auto loc = glGetUniformLocation(progText.m_program, "colour"); loc >= 0) {
+ glUniform3fv(loc, 1, glm::value_ptr(colour));
+ }
}
diff --git a/gfx/gl/uiShader.h b/gfx/gl/uiShader.h
index 45ccc23..502ba13 100644
--- a/gfx/gl/uiShader.h
+++ b/gfx/gl/uiShader.h
@@ -4,17 +4,19 @@
#include "programHandle.h"
#include <GL/glew.h>
#include <cstddef>
+#include <glm/glm.hpp>
class UIShader {
public:
UIShader(std::size_t width, std::size_t height);
- void use() const;
+ void useDefault() const;
+ void useText(glm::vec3) const;
private:
class UIProgramHandle : public ProgramHandleBase {
using ProgramHandleBase::ProgramHandleBase;
};
- UIProgramHandle program;
+ UIProgramHandle progDefault, progText;
};
#endif
diff --git a/iwyu.json b/iwyu.json
index fb07160..8141d67 100644
--- a/iwyu.json
+++ b/iwyu.json
@@ -17,6 +17,14 @@
},
{
"include": [
+ "@\"freetype/.*\"",
+ "private",
+ "<freetype/freetype.h>",
+ "public"
+ ]
+ },
+ {
+ "include": [
"@<glm/detail/.*>",
"private",
"<glm/glm.hpp>",
@@ -121,6 +129,14 @@
},
{
"symbol": [
+ "FT_FREETYPE_H",
+ "private",
+ "<ft2build.h>",
+ "public"
+ ]
+ },
+ {
+ "symbol": [
"std::abs",
"private",
"<cmath>",
diff --git a/lib/unicode.c b/lib/unicode.c
new file mode 100644
index 0000000..b52431f
--- /dev/null
+++ b/lib/unicode.c
@@ -0,0 +1,13 @@
+#include "unicode.h"
+#include <glib.h>
+
+const char *
+next_char(const char * c)
+{
+ return g_utf8_next_char(c);
+}
+uint32_t
+get_codepoint(const char * c)
+{
+ return g_utf8_get_char(c);
+}
diff --git a/lib/unicode.h b/lib/unicode.h
new file mode 100644
index 0000000..8bd841b
--- /dev/null
+++ b/lib/unicode.h
@@ -0,0 +1,20 @@
+#ifndef UNICODE_H
+#define UNICODE_H
+
+// Wrappers of some glib functions (why are we using glib then?) which we want, but glib.h is a bit C like
+
+#ifdef __cplusplus
+# include <cstdint>
+extern "C" {
+#else
+# include <stdint.h>
+#endif
+
+const char * next_char(const char *);
+uint32_t get_codepoint(const char *);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/test/Jamfile.jam b/test/Jamfile.jam
index 82ca894..f8987d0 100644
--- a/test/Jamfile.jam
+++ b/test/Jamfile.jam
@@ -24,3 +24,4 @@ run test-obj.cpp ;
run test-maths.cpp ;
run test-network.cpp ;
run test-persistence.cpp : -- : [ sequence.insertion-sort [ glob fixtures/json/*.json fixtures/json/bad/*.json ] ] ;
+run test-text.cpp ;
diff --git a/test/test-text.cpp b/test/test-text.cpp
new file mode 100644
index 0000000..93a831e
--- /dev/null
+++ b/test/test-text.cpp
@@ -0,0 +1,91 @@
+#define BOOST_TEST_MODULE test_text
+
+#include "test-helpers.hpp"
+#include <boost/test/data/test_case.hpp>
+#include <boost/test/unit_test.hpp>
+#include <stream_support.hpp>
+
+#include <ui/font.h>
+
+struct FontTest : public Font {
+ FontTest() : Font {"/usr/share/fonts/corefonts/arial.ttf", 48} { }
+};
+
+BOOST_TEST_DONT_PRINT_LOG_VALUE(Font::CharData);
+
+using TextureSizeTestData = std::tuple<unsigned, unsigned, unsigned>;
+BOOST_DATA_TEST_CASE(fontTextureSize, boost::unit_test::data::make<unsigned>({2, 3, 10, 50, 250}), fontHeight)
+{
+ auto isPowerOfTwo = [](auto x) {
+ return (x & (x - 1)) == 0;
+ };
+ const auto res = Font::getTextureSize(fontHeight);
+ // Power of 2 dimensions...
+ BOOST_CHECK(isPowerOfTwo(res.x));
+ BOOST_CHECK(isPowerOfTwo(res.y));
+ // No bigger than max texture size...
+ BOOST_CHECK_LE(res.x, GL_MAX_TEXTURE_SIZE);
+ BOOST_CHECK_LE(res.y, GL_MAX_TEXTURE_SIZE);
+ // Big enough to hold the raster...
+ BOOST_CHECK_GE(res.y, 8); // Sensible minimum
+ BOOST_CHECK_GE(res.y, fontHeight);
+ // Keep the requested size
+ BOOST_CHECK_EQUAL(res.z, fontHeight);
+}
+
+BOOST_FIXTURE_TEST_SUITE(ft, FontTest);
+
+BOOST_AUTO_TEST_CASE(initialize_chardata)
+{
+ BOOST_CHECK_GE(charsData.size(), 72);
+ BOOST_CHECK_EQUAL(fontTextures.size(), 2);
+}
+
+using CharDataTest = std::tuple<char, Font::CharData>;
+BOOST_DATA_TEST_CASE(initialize_chardata_A,
+ boost::unit_test::data::make<CharDataTest>({
+ {'A', {0, {34, 35}, {627, 0}, {-1, 35}, 32}},
+ {'I', {0, {6, 35}, {862, 0}, {4, 35}, 13}},
+ {'j', {0, {11, 45}, {1656, 0}, {-3, 35}, 11}},
+ {'o', {0, {24, 27}, {1748, 0}, {1, 27}, 27}},
+ }),
+ character, expected)
+{
+ const auto & cd = charsData.at(character);
+ BOOST_CHECK_EQUAL(cd.textureIdx, expected.textureIdx);
+ BOOST_CHECK_EQUAL(cd.size, expected.size);
+ BOOST_CHECK_EQUAL(cd.position, expected.position);
+ BOOST_CHECK_EQUAL(cd.bearing, expected.bearing);
+ BOOST_CHECK_EQUAL(cd.advance, expected.advance);
+}
+
+static_assert(glm::vec2 {862, 0} / glm::vec2 {2048, 64} == glm::vec2 {0.4208984375, 0});
+static_assert(glm::vec2 {866, 35} / glm::vec2 {2048, 64} == glm::vec2 {0.4228515625, 0.546875});
+
+BOOST_AUTO_TEST_CASE(render_text)
+{
+ constexpr std::string_view text {"I Like Trains"};
+ const auto spaces = std::count_if(text.begin(), text.end(), isspace);
+ const auto tqs = render(text);
+ BOOST_REQUIRE_EQUAL(tqs.size(), 1);
+ const auto & t1 = tqs.begin();
+ BOOST_CHECK_EQUAL(t1->first, fontTextures.front().texture);
+ const auto & v = t1->second;
+ BOOST_CHECK_EQUAL(v.size(), text.size() - spaces);
+
+ BOOST_TEST_CONTEXT(size) {
+ // I
+ BOOST_CHECK_CLOSE_VEC(v[0][0], glm::vec4(4, 0, 0.42, 0.54));
+ BOOST_CHECK_CLOSE_VEC(v[0][1], glm::vec4(10, 0, 0.42, 0.54));
+ BOOST_CHECK_CLOSE_VEC(v[0][2], glm::vec4(10, 35, 0.42, 0));
+ BOOST_CHECK_CLOSE_VEC(v[0][3], glm::vec4(4, 35, 0.42, 0));
+ // (space, no glyph)
+ // L
+ BOOST_CHECK_CLOSE_VEC(v[1][0], glm::vec4(32, 0, 0.42, 0.54));
+ BOOST_CHECK_CLOSE_VEC(v[1][1], glm::vec4(54, 0, 0.42, 0.54));
+ BOOST_CHECK_CLOSE_VEC(v[1][2], glm::vec4(54, 35, 0.42, 0));
+ BOOST_CHECK_CLOSE_VEC(v[1][3], glm::vec4(32, 35, 0.42, 0));
+ }
+}
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/ui/font.cpp b/ui/font.cpp
new file mode 100644
index 0000000..5596f20
--- /dev/null
+++ b/ui/font.cpp
@@ -0,0 +1,182 @@
+#include "font.h"
+#include <algorithm>
+#include <cctype>
+#include <ft2build.h>
+#include FT_FREETYPE_H
+#include <glRef.hpp>
+#include <maths.h>
+#include <memory>
+#include <optional>
+#include <stdexcept>
+#include <unicode.h>
+#include <utility>
+// IWYU pragma: no_forward_declare FT_LibraryRec_
+
+std::string
+FT_Error_StringSafe(FT_Error err)
+{
+ if (const auto errstr = FT_Error_String(err)) {
+ return {errstr};
+ }
+ return std::to_string(err);
+}
+
+template<auto Func, typename... Args>
+void
+FT_Check(Args &&... args)
+{
+ if (const auto err = Func(std::forward<Args>(args)...)) {
+ throw std::runtime_error {std::string {"FreeType error: "} + FT_Error_StringSafe(err)};
+ }
+}
+
+const std::string BASIC_CHARS = []() {
+ std::string chars;
+ for (char c {}; c >= 0; c++) {
+ if (isgraph(c)) {
+ chars += c;
+ }
+ }
+ return chars + "£€²³";
+}();
+
+using FT = glRef<FT_Library,
+ []() {
+ FT_Library ft {};
+ FT_Check<FT_Init_FreeType>(&ft);
+ return ft;
+ },
+ FT_Done_FreeType>;
+
+using Face = glRef<FT_Face,
+ [](FT_Library ft, const char * const name) {
+ FT_Face face {};
+ FT_Check<FT_New_Face>(ft, name, 0, &face);
+ return face;
+ },
+ FT_Done_Face>;
+
+Font::Font(const char * const p, unsigned s) : path {p}, size {getTextureSize(s)}
+{
+ generateChars(BASIC_CHARS);
+}
+
+void
+Font::generateChars(const std::string_view chars) const
+{
+ std::optional<FT> ft;
+ std::optional<Face> face;
+
+ for (auto c = chars.data(); c <= &chars.back(); c = next_char(c)) {
+ const auto codepoint = get_codepoint(c);
+ if (charsData.find(codepoint) == charsData.end()) {
+ if (!ft) {
+ ft.emplace();
+ }
+ if (!face) {
+ face.emplace(*ft, path.c_str());
+ FT_Set_Pixel_Sizes(*face, 0, size.z);
+ }
+ FT_UInt glyph_index = FT_Get_Char_Index(*face, codepoint);
+ if (FT_Load_Glyph(*face, glyph_index, FT_LOAD_RENDER)) {
+ charsData.emplace(codepoint, CharData {});
+ continue;
+ }
+
+ const auto & glyph = (*face)->glyph;
+ const auto textureIdx = getTextureWithSpace(glyph->bitmap.width);
+ auto & texture = fontTextures[textureIdx];
+
+ glTexSubImage2D(GL_TEXTURE_2D, 0, static_cast<GLint>(texture.used), 0,
+ static_cast<GLsizei>(glyph->bitmap.width), static_cast<GLsizei>(glyph->bitmap.rows), GL_RED,
+ GL_UNSIGNED_BYTE, glyph->bitmap.buffer);
+
+ const auto & cd = charsData
+ .emplace(codepoint,
+ CharData {textureIdx, {glyph->bitmap.width, glyph->bitmap.rows},
+ {texture.used, 0}, {glyph->bitmap_left, glyph->bitmap_top},
+ glyph->advance.x >> 6})
+ .first->second;
+ texture.used += cd.size.x;
+ }
+ }
+}
+
+std::size_t
+Font::getTextureWithSpace(unsigned int adv) const
+{
+ if (auto itr = std::find_if(fontTextures.begin(), fontTextures.end(),
+ [adv, this](const FontTexture & ft) {
+ return (ft.used + adv) < size.x;
+ });
+ itr != fontTextures.end()) {
+ glBindTexture(GL_TEXTURE_2D, itr->texture);
+ return static_cast<std::size_t>(itr - fontTextures.begin());
+ }
+
+ auto & texture = fontTextures.emplace_back();
+ glGenTextures(1, &texture.texture);
+ glBindTexture(GL_TEXTURE_2D, texture.texture);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RED, static_cast<GLsizei>(size.x), static_cast<GLsizei>(size.y), 0, GL_RED,
+ GL_UNSIGNED_BYTE, nullptr);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+
+ return fontTextures.size() - 1;
+}
+
+glm::uvec3
+Font::getTextureSize(unsigned int height)
+{
+ auto pow2 = [](unsigned int target) {
+ unsigned int v {8};
+ do {
+ v <<= 1;
+ } while (v << 1 < GL_MAX_TEXTURE_SIZE && v < target);
+ return v;
+ };
+
+ constexpr const unsigned int WIDTH_PER_HEIGHT {64};
+ return {pow2(height * WIDTH_PER_HEIGHT), pow2(height), height};
+}
+
+Font::TextureQuads
+Font::render(const std::string_view chars) const
+{
+ constexpr static const std::array<std::pair<glm::vec2, glm::vec2>, 4> C {{
+ {{0, 0}, {0, 1}},
+ {{1, 0}, {1, 1}},
+ {{1, 1}, {1, 0}},
+ {{0, 1}, {0, 0}},
+ }};
+
+ generateChars(chars);
+
+ glm::vec2 pos {};
+ TextureQuads out;
+ for (auto c = chars.data(); c <= &chars.back(); c = next_char(c)) {
+ if (isspace(*c)) {
+ pos.x += static_cast<float>(size.y) / 4.F;
+ continue;
+ }
+ const auto & ch = charsData.at(get_codepoint(c));
+ if (!ch.advance) {
+ continue;
+ }
+
+ const auto charPos = pos + glm::vec2 {ch.bearing.x, ch.bearing.y - static_cast<int>(ch.size.y)};
+ const auto size = glm::vec2 {ch.size};
+
+ Quad q;
+ std::transform(C.begin(), C.end(), q.begin(), [&size, &charPos, &ch, this](const auto & c) {
+ return (charPos + (size * c.first))
+ || ((glm::vec2 {ch.position} + (glm::vec2 {ch.size} * c.second)) / glm::vec2 {this->size});
+ });
+ out[fontTextures[ch.textureIdx].texture].emplace_back(q);
+
+ pos.x += static_cast<float>(ch.advance);
+ }
+ return out;
+}
diff --git a/ui/font.h b/ui/font.h
new file mode 100644
index 0000000..c9d834a
--- /dev/null
+++ b/ui/font.h
@@ -0,0 +1,48 @@
+#ifndef FONT_H
+#define FONT_H
+
+#include <GL/glew.h>
+#include <array>
+#include <cstddef>
+#include <cstdint>
+#include <glm/glm.hpp>
+#include <map>
+#include <string>
+#include <string_view>
+#include <vector>
+
+class Font {
+public:
+ Font(const char * const path, unsigned int height);
+
+ using Quad = std::array<glm::vec4, 4>;
+ using Quads = std::vector<Quad>;
+ using TextureQuads = std::map<GLuint /*textureId*/, Quads>;
+ TextureQuads render(const std::string_view text) const;
+
+ struct CharData {
+ size_t textureIdx;
+ glm::uvec2 size;
+ glm::uvec2 position;
+ glm::ivec2 bearing;
+ long advance;
+ };
+ struct FontTexture {
+ GLuint texture;
+ unsigned int used;
+ };
+
+ static glm::uvec3 getTextureSize(unsigned int height);
+
+protected:
+ void generateChars(const std::string_view text) const;
+ const CharData getChar(char) const;
+ std::size_t getTextureWithSpace(unsigned int adv) const;
+
+ std::string path;
+ glm::uvec3 size;
+ mutable std::map<uint32_t, CharData> charsData;
+ mutable std::vector<FontTexture> fontTextures;
+};
+
+#endif
diff --git a/ui/text.cpp b/ui/text.cpp
new file mode 100644
index 0000000..be696c3
--- /dev/null
+++ b/ui/text.cpp
@@ -0,0 +1,59 @@
+#include "text.h"
+#include "font.h"
+#include "gfx/gl/uiShader.h"
+#include "uiComponent.h"
+#include <array>
+#include <glBuffers.h>
+#include <glVertexArrays.h>
+#include <glm/gtc/type_ptr.hpp>
+#include <map>
+#include <utility>
+
+const auto font {"/usr/share/fonts/hack/Hack-Regular.ttf"};
+Text::Text(std::string_view s, Position pos, glm::vec3 c) : UIComponent {pos}, colour {c}
+{
+ for (const auto & textureQuads : Font {font, static_cast<unsigned int>(pos.size.y)}.render(s)) {
+ auto & rendering
+ = models.emplace_back(textureQuads.first, static_cast<GLsizei>(6 * textureQuads.second.size()));
+ glBindVertexArray(rendering.vao);
+
+ glBindBuffer(GL_ARRAY_BUFFER, rendering.vbo);
+ std::vector<glm::vec4> vertices;
+ vertices.reserve(6 * textureQuads.second.size());
+ for (const auto & quad : textureQuads.second) {
+ for (auto offset = 0U; offset < 3; offset += 2) {
+ for (auto vertex = 0U; vertex < 3; vertex += 1) {
+ vertices.emplace_back(quad[(vertex + offset) % 4] + glm::vec4 {position.origin, 0, 0});
+ }
+ }
+ };
+ glBufferData(GL_ARRAY_BUFFER, static_cast<GLsizeiptr>(sizeof(glm::vec4)) * rendering.count,
+ glm::value_ptr(vertices.front()), GL_STATIC_DRAW);
+
+ glEnableVertexAttribArray(0);
+ glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, sizeof(glm::vec4), nullptr);
+
+ glBindVertexArray(0);
+ }
+}
+
+void
+Text::render(const UIShader & shader, const Position &) const
+{
+ shader.useText(colour);
+ for (const auto & m : models) {
+ glBindTexture(GL_TEXTURE_2D, m.texture);
+ glBindVertexArray(m.vao);
+ glDrawArrays(GL_TRIANGLES, 0, m.count);
+ }
+ glBindVertexArray(0);
+ glBindTexture(GL_TEXTURE_2D, 0);
+}
+
+bool
+Text::handleInput(const SDL_Event &, const Position &)
+{
+ return false;
+}
+
+Text::Model::Model(GLuint t, GLsizei c) : texture {t}, count {c} { }
diff --git a/ui/text.h b/ui/text.h
new file mode 100644
index 0000000..81122de
--- /dev/null
+++ b/ui/text.h
@@ -0,0 +1,31 @@
+#pragma once
+
+#include "uiComponent.h"
+#include <GL/glew.h>
+#include <glBuffers.h>
+#include <glVertexArrays.h>
+#include <glm/glm.hpp>
+#include <string_view>
+#include <vector>
+
+class UIShader;
+union SDL_Event;
+
+class Text : public UIComponent {
+public:
+ Text(std::string_view s, Position, glm::vec3 colour);
+
+ void render(const UIShader &, const Position & parentPos) const override;
+ bool handleInput(const SDL_Event &, const Position & parentPos) override;
+
+private:
+ struct Model {
+ Model(GLuint, GLsizei);
+ GLuint texture;
+ GLsizei count;
+ glVertexArray vao;
+ glBuffer vbo;
+ };
+ std::vector<Model> models;
+ glm::vec3 colour;
+};
diff --git a/ui/toolbar.cpp b/ui/toolbar.cpp
index c8febce..ada97b0 100644
--- a/ui/toolbar.cpp
+++ b/ui/toolbar.cpp
@@ -1,4 +1,5 @@
#include "toolbar.h"
+#include "gfx/gl/uiShader.h"
#include "ui/iconButton.h"
#include "ui/uiComponent.h"
#include "uiComponentPlacer.h"
@@ -17,6 +18,7 @@ Toolbar::Toolbar(const std::initializer_list<InitInfo> & initInfo) : UIComponent
void
Toolbar::render(const UIShader & uiShader, const Position & parentPos) const
{
+ uiShader.useDefault();
const auto absPos = this->position + parentPos;
icons.apply(&UIComponent::render, uiShader, absPos);
}
diff --git a/ui/window.cpp b/ui/window.cpp
index 13c7d95..6a263aa 100644
--- a/ui/window.cpp
+++ b/ui/window.cpp
@@ -13,6 +13,7 @@ SDL_GL_CreateContextAndGlewInit(SDL_Window * w)
if (glewInit() != GLEW_OK) {
throw std::runtime_error {"Glew failed to initialize!"};
}
+ glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
glEnable(GL_CULL_FACE);
glCullFace(GL_BACK);
glEnable(GL_BLEND);
@@ -89,7 +90,6 @@ Window::refresh(const GameState * gameState) const
void
Window::render(const GameState *) const
{
- uiShader.use();
glDisable(GL_DEPTH_TEST);
uiComponents.apply(&UIComponent::render, uiShader, UIComponent::Position {});
}