From 1a200205a54ccd738390da32c46dc88f2bb94314 Mon Sep 17 00:00:00 2001 From: Corentin Date: Tue, 13 Jul 2021 00:35:45 +0900 Subject: [PATCH] Fix text rendering --- .clang-format | 121 ++++++++++++++++++++++++++++ include/uui/opengl/application.hpp | 5 +- include/uui/opengl/font_manager.hpp | 4 +- include/uui/opengl/label.hpp | 2 +- make.py | 17 +--- src/test/benchmark_text.cpp | 28 +++++++ src/test/example_gl.cpp | 11 ++- src/uui/opengl/application.cpp | 14 +++- src/uui/opengl/component.cpp | 6 -- src/uui/opengl/font_manager.cpp | 31 +++---- src/uui/opengl/label.cpp | 4 +- src/uui/opengl/window.cpp | 39 ++++----- 12 files changed, 214 insertions(+), 68 deletions(-) create mode 100644 .clang-format create mode 100644 src/test/benchmark_text.cpp diff --git a/.clang-format b/.clang-format new file mode 100644 index 0000000..f54912e --- /dev/null +++ b/.clang-format @@ -0,0 +1,121 @@ +BasedOnStyle: Microsoft +AccessModifierOffset: -3 +AlignAfterOpenBracket: AlwaysBreak +AlignConsecutiveAssignments: None +AlignConsecutiveBitFields: None +AlignConsecutiveDeclarations: None +AlignConsecutiveMacros: None +AlignEscapedNewlines: DontAlign +AlignOperands: DontAlign +AlignTrailingComments: false +AllowAllArgumentsOnNextLine: true +AllowAllConstructorInitializersOnNextLine: true +AllowAllParametersOfDeclarationOnNextLine: true +AllowShortBlocksOnASingleLine: Empty +AllowShortCaseLabelsOnASingleLine: false +AllowShortEnumsOnASingleLine: true +AllowShortFunctionsOnASingleLine: Inline +AllowShortIfStatementsOnASingleLine: Never +AllowShortLambdasOnASingleLine: All +AllowShortLoopsOnASingleLine: true +AlwaysBreakAfterReturnType: None +AlwaysBreakBeforeMultilineStrings: false +AlwaysBreakTemplateDeclarations: No +AttributeMacros: ['__ununsed'] +BinPackArguments: true +BinPackParameters: true +BitFieldColonSpacing: Both +BraceWrapping: + AfterCaseLabel: true + AfterClass: true + AfterControlStatement: Always + AfterEnum: true + AfterFunction: true + AfterNamespace: true + AfterStruct: true + AfterUnion: true + AfterExternBlock: true + BeforeCatch: true + BeforeElse: true + BeforeLambdaBody: false + BeforeWhile: true + IndentBraces: false + SplitEmptyFunction: false + SplitEmptyRecord: false + SplitEmptyNamespace: false +BreakBeforeBinaryOperators: NonAssignment +BreakBeforeBraces: Custom +BreakBeforeConceptDeclarations: false +BreakBeforeTernaryOperators: true +BreakConstructorInitializers: AfterColon +BreakInheritanceList: AfterColon +BreakStringLiterals: true +ColumnLimit: 140 +CompactNamespaces: false +ConstructorInitializerAllOnOneLineOrOnePerLine: false +Cpp11BracedListStyle: true +DeriveLineEnding: true +DerivePointerAlignment: false +EmptyLineBeforeAccessModifier: LogicalBlock +FixNamespaceComments: true +IncludeBlocks: Regroup +IncludeCategories: + - Regex: '^<(concept|chrono)' + Priority: 2 + SortPriority: 2 + - Regex: '^' + Priority: 3 + SortPriority: 3 + - Regex: '^<.*/' + Priority: 3 + SortPriority: 3 + - Regex: '^<' + Priority: 2 + SortPriority: 2 + - Regex: '^"' + Priority: 4 + SortPriority: 4 +IndentCaseBlocks: true +IndentCaseLabels: true +IndentExternBlock: NoIndent +IndentGotoLabels: false +IndentPPDirectives: BeforeHash +IndentRequires: true +IndentWidth: 3 +IndentWrappedFunctionNames: false +InsertTrailingCommas: None +KeepEmptyLinesAtTheStartOfBlocks: false +MaxEmptyLinesToKeep: 1 +NamespaceIndentation: None +PointerAlignment: Left +ReflowComments: true +SortIncludes: true +SortUsingDeclarations: true +SpaceAfterCStyleCast: false +SpaceAfterLogicalNot: false +SpaceAfterTemplateKeyword: false +SpaceAroundPointerQualifiers: Before +SpaceBeforeAssignmentOperators: true +SpaceBeforeCaseColon: false +SpaceBeforeCpp11BracedList: true +SpaceBeforeCtorInitializerColon: false +SpaceBeforeInheritanceColon: false +SpaceBeforeParens: Never +SpaceBeforeRangeBasedForLoopColon: false +SpaceBeforeSquareBrackets: false +SpaceInEmptyBlock: false +SpaceInEmptyParentheses: false +SpacesBeforeTrailingComments: 1 +SpacesInAngles: false +SpacesInCStyleCastParentheses: false +SpacesInConditionalStatement: false +SpacesInContainerLiterals: false +SpacesInParentheses: false +SpacesInSquareBrackets: false +Standard: c++17 +TabWidth: 3 +UseCRLF: false +UseTab: Always \ No newline at end of file diff --git a/include/uui/opengl/application.hpp b/include/uui/opengl/application.hpp index 31fa0da..df15fe4 100644 --- a/include/uui/opengl/application.hpp +++ b/include/uui/opengl/application.hpp @@ -64,7 +64,8 @@ protected: int width; int height; - bool need_resize_refresh; + bool render_needed; + bool resize_needed; bool iconified; @@ -79,7 +80,7 @@ protected: void init(); void deinit(); - void draw(); + void render(); static void glfw_resize_callback(GLFWwindow* window, int width, int height); static void glfw_iconify_callback(GLFWwindow* window, int iconified); diff --git a/include/uui/opengl/font_manager.hpp b/include/uui/opengl/font_manager.hpp index 3e1d7d3..07184a5 100644 --- a/include/uui/opengl/font_manager.hpp +++ b/include/uui/opengl/font_manager.hpp @@ -35,7 +35,7 @@ public: struct Font { character_info char_infos[256]; - GLuint tex; + GLuint atlas_texture; unsigned int atlas_width; unsigned int atlas_height; }; @@ -51,7 +51,7 @@ public: std::tuple get_text_size(const std::string& text, Font& font, float scale_x, float scale_y); private: - static constexpr int MAX_WIDTH = 1024; + static constexpr int ATLAS_MAX_WIDTH = 1024; bool initialized; diff --git a/include/uui/opengl/label.hpp b/include/uui/opengl/label.hpp index e589d26..fcb1d24 100644 --- a/include/uui/opengl/label.hpp +++ b/include/uui/opengl/label.hpp @@ -18,7 +18,7 @@ class GlLabel: public GlComponent protected: std::string text; - const std::tuple& text_color; + std::tuple text_color; int text_width; int text_height; diff --git a/make.py b/make.py index 8b6748e..7799daf 100644 --- a/make.py +++ b/make.py @@ -9,7 +9,7 @@ from umake import get_hash, make class Config: CC = 'g++' - APPS = ['test/example_gl'] + APPS = ['test/example_gl', 'test/benchmark_text'] IGNORE_APPS = [] JOB_COUNT = int(os.cpu_count() * 0.8) @@ -20,7 +20,7 @@ class Config: COMMON_FLAGS = '-std=c++17 -fno-semantic-interposition' COMMON_DEBUG_FLAGS = '-g -DDEBUG' - COMMON_RELEASE_FLAGS = '-O2' # -flto' + COMMON_RELEASE_FLAGS = '-O2 -flto' COMPILE_FLAGS = f'-Wall -I{INCLUDE_DIR} `pkg-config --cflags glfw3 vulkan gl x11 freetype2`' LINK_FLAGS = '-lpthread -ldl `pkg-config --libs glfw3 vulkan gl x11 freetype2`' @@ -31,19 +31,6 @@ class Config: def main(): def pre_compile(): -<<<<<<< HEAD -======= - # Compiling vulkan shaders - # for shader_path in ( - # list((Config.SOURCE_DIR / 'uui' / 'vulkan').rglob('*.vert')) - # + list((Config.SOURCE_DIR / 'uui' / 'vulkan').rglob('*.frag'))): - # out_path = Config.BIN_DIR / shader_path.relative_to(Config.SOURCE_DIR) - # if not out_path.parent.exists(): - # out_path.parent.mkdir(parents=True) - # if subprocess.run(['glslc', str(shader_path), '-o', str(out_path) + '.spv']).returncode != 0: - # print(f'Error while compiling shader {shader_path}') - # return ->>>>>>> 675cbbf (Correct resize and safer pointers) # Copying OpenGL shaders src_opengl_shader_path = Config.SOURCE_DIR / 'uui' / 'opengl' / 'shaders' for shader_path in ( diff --git a/src/test/benchmark_text.cpp b/src/test/benchmark_text.cpp new file mode 100644 index 0000000..d51a978 --- /dev/null +++ b/src/test/benchmark_text.cpp @@ -0,0 +1,28 @@ +#include + +#include "uui/opengl/application.hpp" +#include "uui/opengl/component.hpp" +#include "uui/opengl/label.hpp" + +using namespace std; + +int main() +{ + try + { + uui::GlApplication app; + // uui::GlApplication app2; // exception : application already created + auto window = app.create_window(800, 600, "OpenGl!"); + for(int i = 0; i < 100; i += 1) + window->create_label(4*i, 4*i, "Hello World!", {1.0f, 1.0f, 1.0f, 0.5f}); + app.run(); + } + catch(const std::exception& error) + { + std::cerr << error.what() << std::endl; + return EXIT_FAILURE; + } + + cout << "Example done" << endl; + return 0; +} diff --git a/src/test/example_gl.cpp b/src/test/example_gl.cpp index 708f533..8f82bb9 100644 --- a/src/test/example_gl.cpp +++ b/src/test/example_gl.cpp @@ -15,10 +15,13 @@ int main() uui::GlApplication app; // uui::GlApplication app2; // exception : application already created auto window = app.create_window(800, 600, "OpenGl!"); - auto comp = window->create_component(0, 100, 0.5f, 50); - comp->set_background_color(0.8f, 0.1f, 0.5f); - auto label = window->create_label(0.5f, 0.5f, "Hello World!", {1.0f, 1.0f, 1.0f, 0.5f}); - label->set_background_color(0.1f, 0.5f, 0.1f); + // auto comp = window->create_component(0, 100, 0.5f, 50); + // comp->set_background_color(0.8f, 0.1f, 0.5f); + auto label = window->create_label(50, 50, "Hello World!", {0.5f, 1.0f, 0.5f, 1.0f}); + label->set_background_color(0.1f, 0.2f, 0.5f); + label = window->create_label(0.5f, 0.5f, "Hello World!", {1.0f, 1.0f, 1.0f, 0.5f}); + label->set_background_color(0.5f, 0.5f, 0.1f); + label = window->create_label(0.75f, 0.75f, "Hello World!", {1.0f, 1.0f, 1.0f, 0.1f}); app.run(); } // cout << "\nStarting example 2" << endl; diff --git a/src/uui/opengl/application.cpp b/src/uui/opengl/application.cpp index 8c3d07f..79ed9c6 100644 --- a/src/uui/opengl/application.cpp +++ b/src/uui/opengl/application.cpp @@ -59,8 +59,10 @@ void uui::GlApplication::run() frame_count = 0.0f; start_time = end_time; } + glfwPollEvents(); } - glfwPollEvents(); + else + glfwWaitEvents(); // Destroying windows for(auto it = windows.begin(); it != windows.end(); it += 1) @@ -78,7 +80,15 @@ void uui::GlApplication::run() it -= 1; } else - window->draw(); + { + if constexpr(debug_mode) + window->render(); + else + { + if(window->render_needed && !window->iconified) + window->render(); + } + } } if constexpr(debug_mode) frame_count += 1; diff --git a/src/uui/opengl/component.cpp b/src/uui/opengl/component.cpp index 4b83875..922c016 100644 --- a/src/uui/opengl/component.cpp +++ b/src/uui/opengl/component.cpp @@ -104,11 +104,7 @@ void uui::GlComponent::set_vbo_data() }; // clang-format on glBindBuffer(GL_ARRAY_BUFFER, gl_vbo); - if constexpr(uui::GlApplication::debug_mode) - _glCheckError(); glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW); - if constexpr(uui::GlApplication::debug_mode) - _glCheckError(); glVertexAttribPointer( 0, // index @@ -145,8 +141,6 @@ void uui::GlComponent::render() { glBindVertexArray(gl_vao); glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, (void*)0); - if constexpr(uui::GlApplication::debug_mode) - _glCheckError(); } void uui::GlComponent::on_resize() diff --git a/src/uui/opengl/font_manager.cpp b/src/uui/opengl/font_manager.cpp index c368bf5..ec1b478 100644 --- a/src/uui/opengl/font_manager.cpp +++ b/src/uui/opengl/font_manager.cpp @@ -116,7 +116,7 @@ void uui::GlFontManager::deinit() if(!initialized) throw std::runtime_error("GlFontManager error : calling deinit while not initialized"); - for(const auto& font: fonts) glDeleteTextures(1, &font.tex); + for(const auto& font: fonts) glDeleteTextures(1, &font.atlas_texture); glDeleteBuffers(1, &gl_vbo); glDeleteBuffers(1, &gl_vao); glDeleteProgram(gl_program); @@ -128,6 +128,7 @@ const uui::GlFontManager::Font& uui::GlFontManager::init_font(const std::string& { fonts.emplace_back(); auto& font = fonts.back(); + FT_Face face; if(FT_New_Face(ft, font_path.c_str(), 0, &face)) throw std::runtime_error("ERROR::FREETYPE: Failed to load font"); @@ -141,14 +142,14 @@ const uui::GlFontManager::Font& uui::GlFontManager::init_font(const std::string& memset(font.char_infos, 0, sizeof(font.char_infos)); // Find minimum size for a texture holding all visible ASCII characters - for(int i = 32; i < 128; i++) + for(int i = 32; i < 256; i++) { if(FT_Load_Char(face, i, FT_LOAD_RENDER)) { std::cout << "GlFontManager warning : loading character " << i << " failed!" << std::endl; continue; } - if(row_width + glyph->bitmap.width + 1 >= MAX_WIDTH) + if(row_width + glyph->bitmap.width + 1 >= ATLAS_MAX_WIDTH) { font.atlas_width = std::max(font.atlas_width, row_width); font.atlas_height += row_height; @@ -166,8 +167,8 @@ const uui::GlFontManager::Font& uui::GlFontManager::init_font(const std::string& // Create a texture that will be used to hold all ASCII glyphs glActiveTexture(GL_TEXTURE0); - glGenTextures(1, &font.tex); - glBindTexture(GL_TEXTURE_2D, font.tex); + glGenTextures(1, &font.atlas_texture); + glBindTexture(GL_TEXTURE_2D, font.atlas_texture); glTexImage2D(GL_TEXTURE_2D, 0, GL_RED, font.atlas_width, font.atlas_height, 0, GL_RED, GL_UNSIGNED_BYTE, 0); @@ -188,7 +189,7 @@ const uui::GlFontManager::Font& uui::GlFontManager::init_font(const std::string& row_height = 0; - for(int i = 32; i < 128; i++) + for(int i = 32; i < 256; i++) { if(FT_Load_Char(face, i, FT_LOAD_RENDER)) { @@ -196,7 +197,7 @@ const uui::GlFontManager::Font& uui::GlFontManager::init_font(const std::string& continue; } - if(offset_x + glyph->bitmap.width + 1 >= MAX_WIDTH) + if(offset_x + glyph->bitmap.width + 1 >= ATLAS_MAX_WIDTH) { offset_y += row_height; row_height = 0; @@ -254,7 +255,7 @@ void uui::GlFontManager::render_text( glBindVertexArray(gl_vao); // Use the texture containing the atlas - glBindTexture(GL_TEXTURE_2D, font.tex); + glBindTexture(GL_TEXTURE_2D, font.atlas_texture); std::vector vertices; vertices.resize(24 * text.size()); @@ -269,7 +270,7 @@ void uui::GlFontManager::render_text( const auto& char_info = font.char_infos[static_cast(current_char)]; // Calculate the vertex and texture coordinates float char_x = out_base_x + char_info.bitmap_left * scale_x; - float char_y = -out_base_y - char_info.bitmap_top * scale_y; + float char_y = out_base_y - char_info.bitmap_top * scale_y; float w = char_info.bitmap_width * scale_x; float h = char_info.bitmap_height * scale_y; @@ -283,12 +284,12 @@ void uui::GlFontManager::render_text( // clang-format off float current_vertex[24] = { - char_x, -char_y, char_info.texture_x, char_info.texture_y, // top_left - char_x + w, -char_y, char_info.texture_x + char_info.bitmap_width / font.atlas_width, char_info.texture_y, // top-right - char_x, -char_y - h, char_info.texture_x, char_info.texture_y + char_info.bitmap_height / font.atlas_height, // bottom-right - char_x + w, -char_y, char_info.texture_x + char_info.bitmap_width / font.atlas_width, char_info.texture_y, // top-right - char_x, -char_y - h, char_info.texture_x, char_info.texture_y + char_info.bitmap_height / font.atlas_height, // bottom-left - char_x + w, -char_y - h, char_info.texture_x + char_info.bitmap_width / font.atlas_width, + char_x, char_y, char_info.texture_x, char_info.texture_y, // top_left + char_x + w, char_y, char_info.texture_x + char_info.bitmap_width / font.atlas_width, char_info.texture_y, // top-right + char_x, char_y + h, char_info.texture_x, char_info.texture_y + char_info.bitmap_height / font.atlas_height, // bottom-right + char_x + w, char_y, char_info.texture_x + char_info.bitmap_width / font.atlas_width, char_info.texture_y, // top-right + char_x, char_y + h, char_info.texture_x, char_info.texture_y + char_info.bitmap_height / font.atlas_height, // bottom-left + char_x + w, char_y + h, char_info.texture_x + char_info.bitmap_width / font.atlas_width, char_info.texture_y + char_info.bitmap_height / font.atlas_height // bottom-right }; std::memcpy(vertices.data() + (char_count * 24), current_vertex, 24 * sizeof(float)); diff --git a/src/uui/opengl/label.cpp b/src/uui/opengl/label.cpp index 63aaee2..5ba7478 100644 --- a/src/uui/opengl/label.cpp +++ b/src/uui/opengl/label.cpp @@ -15,9 +15,9 @@ uui::GlLabel::GlLabel( font_index = 0; std::tie(text_width, text_height) = window->font_manager.get_text_size(text, window->font_manager.fonts[font_index], 1.0f, 1.0f); - std::cout << "Text size: " << this->text_width << "x" << text_height << std::endl; size_width = text_width; size_height = text_height; + coord_all_relative = false; } void uui::GlLabel::render() @@ -26,7 +26,7 @@ void uui::GlLabel::render() position_x.index() == 1 ? std::get<1>(position_x) * static_cast(window->width) : static_cast(std::get<0>(position_x)); float text_y = position_y.index() == 1 ? std::get<1>(position_y) * static_cast(window->height) : static_cast(std::get<0>(position_y)); - text_y -= static_cast(text_height) - 1; + text_y += static_cast(text_height) - 1; glBindVertexArray(gl_vao); glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, (void*)0); diff --git a/src/uui/opengl/window.cpp b/src/uui/opengl/window.cpp index d9e7f2a..eb4618c 100644 --- a/src/uui/opengl/window.cpp +++ b/src/uui/opengl/window.cpp @@ -59,9 +59,12 @@ void uui::GlWindow::glfw_resize_callback(GLFWwindow* window, int width, int heig glViewport(0, 0, width, height); gl_window->width = width; gl_window->height = height; - gl_window->need_resize_refresh = true; + gl_window->render_needed = true; + gl_window->resize_needed = true; - glm::mat4 projection = glm::ortho(0.0f, static_cast(width), 0.0f, static_cast(height)); + glm::mat4 projection = glm::ortho(0.0f, static_cast(width), static_cast(height), 0.0f); + glfwMakeContextCurrent(window); + glUseProgram(gl_window->font_manager.gl_program); glUniformMatrix4fv(glGetUniformLocation(gl_window->font_manager.gl_program, "projection"), 1, GL_FALSE, glm::value_ptr(projection)); } @@ -78,7 +81,7 @@ void uui::GlWindow::glfw_key_callback(GLFWwindow* window, int key, int scancode, } uui::GlWindow::GlWindow(uui::GlApplication* app, size_t index, int width, int height, const std::string& title): - app(app), width(width), height(height), need_resize_refresh(false), iconified(false), index(index), initialized(false) + app(app), width(width), height(height), render_needed(true), resize_needed(false), iconified(false), index(index), initialized(false) { if constexpr(uui::GlApplication::debug_mode) std::cout << "Creating a GlWindow" << std::endl; @@ -117,7 +120,7 @@ void uui::GlWindow::init() // glEnable(GL_CULL_FACE); glEnable(GL_BLEND); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glBlendFunc(GL_SRC_ALPHA, GL_DST_ALPHA); if constexpr(uui::GlApplication::debug_mode) { @@ -199,7 +202,7 @@ void uui::GlWindow::init() font_manager.init(); glUseProgram(font_manager.gl_program); - glm::mat4 projection = glm::ortho(0.0f, static_cast(width), 0.0f, static_cast(height)); + glm::mat4 projection = glm::ortho(0.0f, static_cast(width), static_cast(height), 0.0f); glUniformMatrix4fv(glGetUniformLocation(font_manager.gl_program, "projection"), 1, GL_FALSE, glm::value_ptr(projection)); glUseProgram(gl_program); @@ -224,24 +227,22 @@ void uui::GlWindow::deinit() initialized = false; } -void uui::GlWindow::draw() +void uui::GlWindow::render() { - if(!iconified) + glfwMakeContextCurrent(glfw_window); + glClearColor(0.1f, 0.1f, 0.1f, 1.0f); + glClear(GL_COLOR_BUFFER_BIT); + + glUseProgram(gl_program); + if(resize_needed) { - glfwMakeContextCurrent(glfw_window); - glClearColor(0.1f, 0.1f, 0.1f, 1.0f); - glClear(GL_COLOR_BUFFER_BIT); - - glUseProgram(gl_program); - if(need_resize_refresh) - { - for(auto& component: components) component->on_resize(); - need_resize_refresh = false; - } - for(auto& component: components) component->render(); + for(auto& component: components) component->on_resize(); + resize_needed = false; } - + for(auto& component: components) component->render(); glfwSwapBuffers(glfw_window); + + render_needed = false; } std::shared_ptr uui::GlWindow::create_component(