Working FontManager and Label implementation (WIP)

This commit is contained in:
Corentin 2021-07-12 17:30:44 +09:00
commit af6967151e
15 changed files with 608 additions and 61 deletions

View file

@ -2,6 +2,7 @@
#include "uui/opengl/application.hpp"
#include "uui/opengl/component.hpp"
#include "uui/opengl/label.hpp"
using namespace std;
@ -16,21 +17,23 @@ int main()
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);
app.run();
}
cout << "\nStarting example 2" << endl;
{
uui::GlApplication app;
auto window_1 = app.create_window(800, 600, "OpenGl!");
auto comp = window_1->create_component(0.25f, 0.25f, 0.5f, 0.5f);
comp->set_background_color(0.8f, 0.1f, 0.5f);
comp = window_1->create_component(0.75f, 0.75f, 0.25f, 0.25f);
comp->set_background_color(0.2f, 0.1f, 0.5f);
auto window_2 = app.create_window(600, 600, "OpenGL 2!");
comp = window_2->create_component(0, 0.5f, 100, 0.5f);
comp->set_background_color(0.2f, 0.5f, 0.3f);
app.run();
}
// cout << "\nStarting example 2" << endl;
// {
// uui::GlApplication app;
// auto window_1 = app.create_window(800, 600, "OpenGl!");
// auto comp = window_1->create_component(0.25f, 0.25f, 0.5f, 0.5f);
// comp->set_background_color(0.8f, 0.1f, 0.5f);
// comp = window_1->create_component(0.75f, 0.75f, 0.25f, 0.25f);
// comp->set_background_color(0.2f, 0.1f, 0.5f);
// auto window_2 = app.create_window(600, 600, "OpenGL 2!");
// comp = window_2->create_component(0, 0.5f, 100, 0.5f);
// comp->set_background_color(0.2f, 0.5f, 0.3f);
// app.run();
// }
}
catch(const std::exception& error)
{

View file

@ -3,7 +3,7 @@
#include <chrono>
#include <iostream>
uui::GlApplication* uui::GlApplication::application_pointer = nullptr;
uui::GlApplication* uui::GlApplication::application_pointer = nullptr;
uui::GlApplication::GlApplication()
{
@ -28,7 +28,8 @@ uui::GlApplication::GlApplication()
uui::GlApplication::~GlApplication()
{
std::cout << "Destroying the GlApplication" << std::endl;
if constexpr(debug_mode)
std::cout << "Destroying the GlApplication" << std::endl;
windows.clear();
glfwTerminate();
application_pointer = nullptr;
@ -36,23 +37,28 @@ uui::GlApplication::~GlApplication()
void uui::GlApplication::run()
{
std::cout << "Starting the GlApplication" << std::endl;
if constexpr(debug_mode)
std::cout << "Starting the GlApplication" << std::endl;
auto start_time = std::chrono::high_resolution_clock::now();
auto end_time = start_time;
float render_duration;
float frame_count = 0.0f;
std::cout << "\n";
if constexpr(debug_mode)
std::cout << "\n";
while(!windows.empty())
{
end_time = std::chrono::high_resolution_clock::now();
render_duration = std::chrono::duration_cast<std::chrono::milliseconds>(end_time - start_time).count();
// std::cout << "Frame " << frame_count << ", duration: " << render_duration << std::endl;
if(frame_count > 0.0f && render_duration > 500.0f)
if constexpr(debug_mode)
{
std::cout << "\rFPS : " << (frame_count * 1000.0f) / render_duration << " " << std::flush;
frame_count = 0.0f;
start_time = end_time;
end_time = std::chrono::high_resolution_clock::now();
render_duration = std::chrono::duration_cast<std::chrono::milliseconds>(end_time - start_time).count();
// std::cout << "Frame " << frame_count << ", duration: " << render_duration << std::endl;
if(frame_count > 0.0f && render_duration > 500.0f)
{
std::cout << "\rFPS : " << (frame_count * 1000.0f) / render_duration << " " << std::flush;
frame_count = 0.0f;
start_time = end_time;
}
}
glfwPollEvents();
@ -74,9 +80,11 @@ void uui::GlApplication::run()
else
window->draw();
}
frame_count += 1;
if constexpr(debug_mode)
frame_count += 1;
}
std::cout << "Ending the GlApplication" << std::endl;
if constexpr(debug_mode)
std::cout << "Ending the GlApplication" << std::endl;
}
std::shared_ptr<uui::GlWindow> uui::GlApplication::create_window(int width, int height, const std::string& title)

View file

@ -11,7 +11,8 @@ uui::GlComponent::GlComponent(
window(window),
position_x(x), position_y(y), size_width(width), size_height(height), initialized(false)
{
std::cout << "Creating a GlBox" << std::endl;
if constexpr(uui::GlApplication::debug_mode)
std::cout << "Creating a GlBox" << std::endl;
coord_all_relative = true;
auto parse_coords = [&](std::variant<int, float>& value) {
@ -33,7 +34,8 @@ uui::GlComponent::GlComponent(
uui::GlComponent::~GlComponent()
{
std::cout << "Closing a GlBox" << std::endl;
if constexpr(uui::GlApplication::debug_mode)
std::cout << "Closing a GlBox" << std::endl;
if(initialized)
deinit();
}
@ -94,12 +96,12 @@ void uui::GlComponent::set_vbo_data()
float y_min = (-2.0f * vert_y) + 1.0f;
float y_max = y_min - (2.0f * vert_h);
// clang-format off
float vertices[] = {
x_max, y_min, 0.0f, background_color[0] , background_color[1], background_color[2], background_color[3], // top right
x_max, y_max, 0.0f, background_color[0] , background_color[1], background_color[2], background_color[3], // bottom right
x_min, y_max, 0.0f, background_color[0] , background_color[1], background_color[2], background_color[3], // bottom left
x_min, y_min, 0.0f, background_color[0] , background_color[1], background_color[2], background_color[3] // top left
};
float vertices[] = {
x_max, y_min, 0.0f, background_color[0] , background_color[1], background_color[2], background_color[3], // top right
x_max, y_max, 0.0f, background_color[0] , background_color[1], background_color[2], background_color[3], // bottom right
x_min, y_max, 0.0f, background_color[0] , background_color[1], background_color[2], background_color[3], // bottom left
x_min, y_min, 0.0f, background_color[0] , background_color[1], background_color[2], background_color[3] // top left
};
// clang-format on
glBindBuffer(GL_ARRAY_BUFFER, gl_vbo);
if constexpr(uui::GlApplication::debug_mode)

View file

@ -0,0 +1,308 @@
#include "uui/opengl/font_manager.hpp"
#include <cmath>
#include <cstring>
#include <algorithm>
#include <iostream>
#include "uui/opengl/application.hpp"
#include "uui/opengl/gl_utils.hpp"
#include "uui/shader.hpp"
uui::GlFontManager::GlFontManager(): initialized(false) {}
uui::GlFontManager::~GlFontManager()
{
if(initialized)
deinit();
}
void uui::GlFontManager::init()
{
if(initialized)
throw std::runtime_error("GlFontManager error : calling init while initialized");
if constexpr(uui::GlApplication::debug_mode)
std::cout << "Init glFontManager" << std::endl;
if(FT_Init_FreeType(&ft))
throw std::runtime_error("ERROR::FREETYPE: Could not init FreeType Library");
gl_program = glCreateProgram();
// Vertex shader compilation
GLuint vertex_shader = glCreateShader(GL_VERTEX_SHADER);
{
auto vertex_src = readFile("bin/uui/opengl/shaders/text.vert");
auto vertex_str = std::string(vertex_src.begin(), vertex_src.end());
auto vertex_code = vertex_str.c_str();
glShaderSource(vertex_shader, 1, &vertex_code, NULL);
glCompileShader(vertex_shader);
if constexpr(uui::GlApplication::debug_mode)
{
int success;
char info[512];
glGetShaderiv(vertex_shader, GL_COMPILE_STATUS, &success);
if(!success)
{
glGetShaderInfoLog(vertex_shader, 512, NULL, info);
std::cout << "GlBox vertex shader creation error : " << info << std::endl;
}
}
}
// Fragment shader compilation
GLuint fragment_shader = glCreateShader(GL_FRAGMENT_SHADER);
{
auto fragment_src = readFile("bin/uui/opengl/shaders/text.frag");
auto fragment_str = std::string(fragment_src.begin(), fragment_src.end());
auto fragment_code = fragment_str.c_str();
glShaderSource(fragment_shader, 1, &fragment_code, NULL);
glCompileShader(fragment_shader);
if constexpr(uui::GlApplication::debug_mode)
{
int success;
char info[512];
glGetShaderiv(fragment_shader, GL_COMPILE_STATUS, &success);
if(!success)
{
glGetShaderInfoLog(fragment_shader, 512, NULL, info);
std::cout << "GlBox fragment shader creation error : " << info << std::endl;
}
}
}
// Linking shader program
glAttachShader(gl_program, vertex_shader);
if constexpr(uui::GlApplication::debug_mode)
_glCheckError();
glAttachShader(gl_program, fragment_shader);
if constexpr(uui::GlApplication::debug_mode)
_glCheckError();
glLinkProgram(gl_program);
if constexpr(uui::GlApplication::debug_mode)
{
int success;
char info[512];
glGetProgramiv(gl_program, GL_LINK_STATUS, &success);
if(!success)
{
glGetProgramInfoLog(gl_program, 512, NULL, info);
std::cout << "GlBox error : " << info << std::endl;
}
}
glDeleteShader(vertex_shader);
glDeleteShader(fragment_shader);
// init_font("/usr/share/fonts/noto/NotoSans-Regular.ttf", 32);
init_font("FreeSans.ttf", 32);
// Initialize VAO/VBO for rendering
glGenVertexArrays(1, &gl_vao);
glGenBuffers(1, &gl_vbo);
glBindVertexArray(gl_vao);
glBindBuffer(GL_ARRAY_BUFFER, gl_vbo);
glBufferData(GL_ARRAY_BUFFER, sizeof(float) * 6 * 4, NULL, GL_DYNAMIC_DRAW);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 4 * sizeof(float), 0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindVertexArray(0);
initialized = true;
}
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);
glDeleteBuffers(1, &gl_vbo);
glDeleteBuffers(1, &gl_vao);
glDeleteProgram(gl_program);
FT_Done_FreeType(ft);
initialized = false;
}
const uui::GlFontManager::Font& uui::GlFontManager::init_font(const std::string& font_path, size_t font_size)
{
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");
FT_Set_Pixel_Sizes(face, 0, font_size);
FT_GlyphSlot glyph = face->glyph;
unsigned int row_width = 0;
unsigned int row_height = 0;
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++)
{
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)
{
font.atlas_width = std::max(font.atlas_width, row_width);
font.atlas_height += row_height;
row_width = 0;
row_height = 0;
}
row_width += glyph->bitmap.width + 1;
row_height = std::max(row_height, glyph->bitmap.rows);
}
font.atlas_width = std::max(font.atlas_width, row_width);
font.atlas_height += row_height;
glLinkProgram(gl_program);
// 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);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RED, font.atlas_width, font.atlas_height, 0, GL_RED, GL_UNSIGNED_BYTE, 0);
// We require 1 byte alignment when uploading texture data
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
// Clamping to edges is important to prevent artifacts when scaling
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
// Linear filtering usually looks best for text
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
// Paste all glyph bitmaps into the texture, remembering the offset
int offset_x = 0;
int offset_y = 0;
row_height = 0;
for(int i = 32; i < 128; i++)
{
if(FT_Load_Char(face, i, FT_LOAD_RENDER))
{
std::cout << "GlFontManager warning : loading character " << i << " failed!" << std::endl;
continue;
}
if(offset_x + glyph->bitmap.width + 1 >= MAX_WIDTH)
{
offset_y += row_height;
row_height = 0;
offset_x = 0;
}
glTexSubImage2D(
GL_TEXTURE_2D, 0, offset_x, offset_y, glyph->bitmap.width, glyph->bitmap.rows, GL_RED, GL_UNSIGNED_BYTE, glyph->bitmap.buffer);
font.char_infos[i].advance_x = glyph->advance.x >> 6;
font.char_infos[i].advance_y = glyph->advance.y >> 6;
font.char_infos[i].bitmap_width = glyph->bitmap.width;
font.char_infos[i].bitmap_height = glyph->bitmap.rows;
font.char_infos[i].bitmap_left = glyph->bitmap_left;
font.char_infos[i].bitmap_top = glyph->bitmap_top;
font.char_infos[i].texture_x = offset_x / (float)font.atlas_width;
font.char_infos[i].texture_y = offset_y / (float)font.atlas_height;
row_height = std::max(row_height, glyph->bitmap.rows);
offset_x += glyph->bitmap.width + 1;
}
FT_Done_Face(face);
return font;
}
std::tuple<int, int> uui::GlFontManager::get_text_size(
const std::string& text, uui::GlFontManager::Font& font, float scale_x, float scale_y)
{
float width = 0.0f;
float height = 0.0f;
for(auto current_char: text)
{
const auto& char_info = font.char_infos[static_cast<size_t>(current_char)];
width += char_info.advance_x * scale_x;
// height = std::max(height, char_info.bitmap_top + char_info.bitmap_height * scale_y);
height = std::max(height, roundf(char_info.bitmap_height * scale_y));
}
return {static_cast<int>(width), static_cast<int>(height)};
}
void uui::GlFontManager::render_text(
const std::string& text, uui::GlFontManager::Font& font, float x, float y, float scale_x, float scale_y,
const std::tuple<float, float, float, float>& text_color)
{
GLuint gl_prev_program;
glGetIntegerv(GL_CURRENT_PROGRAM, (GLint*)(&gl_prev_program));
glUseProgram(gl_program);
glActiveTexture(GL_TEXTURE0);
auto [color_r, color_g, color_b, color_a] = text_color;
glUniform4f(glGetUniformLocation(gl_program, "textColor"), color_r, color_g, color_b, color_a);
glBindVertexArray(gl_vao);
// Use the texture containing the atlas
glBindTexture(GL_TEXTURE_2D, font.tex);
std::vector<float> vertices;
vertices.resize(24 * text.size());
// vertices.resize(text.size());
int char_count = 0;
// Loop through all characters
float out_base_x = x;
float out_base_y = y;
for(auto current_char: text)
{
const auto& char_info = font.char_infos[static_cast<size_t>(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 w = char_info.bitmap_width * scale_x;
float h = char_info.bitmap_height * scale_y;
// Advance the cursor to the start of the next character
out_base_x += char_info.advance_x * scale_x;
out_base_y += char_info.advance_y * scale_y;
// Skip glyphs that have no pixels
if(!w || !h)
continue;
// 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_info.texture_y + char_info.bitmap_height / font.atlas_height // bottom-right
};
std::memcpy(vertices.data() + (char_count * 24), current_vertex, 24 * sizeof(float));
// clang-format on
char_count += 1;
}
// Draw all the character on the screen in one go
glBindBuffer(GL_ARRAY_BUFFER, gl_vbo);
glBufferData(GL_ARRAY_BUFFER, vertices.size() * sizeof(float), vertices.data(), GL_DYNAMIC_DRAW);
glDrawArrays(GL_TRIANGLES, 0, vertices.size());
// glDisableVertexAttribArray(0);
glBindTexture(GL_TEXTURE_2D, 0);
glBindVertexArray(0);
glUseProgram(gl_prev_program);
}

35
src/uui/opengl/label.cpp Normal file
View file

@ -0,0 +1,35 @@
#include "uui/opengl/label.hpp"
#include <iostream>
#include "uui/opengl/gl_utils.hpp"
uui::GlLabel::GlLabel(
std::shared_ptr<uui::GlWindow> window, const std::variant<int, float> x, const std::variant<int, float> y, const std::string& text,
const std::tuple<float, float, float, float>& text_color):
GlComponent(window, x, y, 0.0f, 0.0f),
text(text), text_color(text_color)
{
if constexpr(uui::GlApplication::debug_mode)
std::cout << "Creating a GlLabel" << std::endl;
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;
}
void uui::GlLabel::render()
{
float text_x =
position_x.index() == 1 ? std::get<1>(position_x) * static_cast<float>(window->width) : static_cast<float>(std::get<0>(position_x));
float text_y =
position_y.index() == 1 ? std::get<1>(position_y) * static_cast<float>(window->height) : static_cast<float>(std::get<0>(position_y));
text_y -= static_cast<float>(text_height) - 1;
glBindVertexArray(gl_vao);
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, (void*)0);
window->font_manager.render_text(text.c_str(), window->font_manager.fonts.front(), text_x, text_y, 1.0f, 1.0f, text_color);
glBindVertexArray(0);
}

View file

@ -0,0 +1,12 @@
#version 460 core
in vec2 textCoords;
out vec4 color;
uniform sampler2D text;
uniform vec4 textColor;
void main(void) {
color = vec4(1.0, 1.0, 1.0, texture2D(text, textCoords).r) * textColor;
}

View file

@ -0,0 +1,12 @@
#version 460 core
layout (location = 0) in vec4 coord;
out vec2 textCoords;
uniform mat4 projection;
void main(void) {
gl_Position = projection * vec4(coord.xy, 0.0, 1.0);
textCoords = coord.zw;
}

View file

@ -4,6 +4,7 @@
#include "uui/opengl/component.hpp"
#include "uui/opengl/gl_utils.hpp"
#include "uui/opengl/label.hpp"
#include "uui/shader.hpp"
static void APIENTRY
@ -59,27 +60,39 @@ void uui::GlWindow::glfw_resize_callback(GLFWwindow* window, int width, int heig
gl_window->width = width;
gl_window->height = height;
gl_window->need_resize_refresh = true;
glm::mat4 projection = glm::ortho(0.0f, static_cast<float>(width), 0.0f, static_cast<float>(height));
glUniformMatrix4fv(glGetUniformLocation(gl_window->font_manager.gl_program, "projection"), 1, GL_FALSE, glm::value_ptr(projection));
}
static void glfw_key_callback(GLFWwindow* window, int key, int scancode, int action, int mods)
void uui::GlWindow::glfw_iconify_callback(GLFWwindow* window, int iconified)
{
auto gl_window = reinterpret_cast<uui::GlWindow*>(glfwGetWindowUserPointer(window));
gl_window->iconified = iconified;
}
void uui::GlWindow::glfw_key_callback(GLFWwindow* window, int key, int scancode, int action, int mods)
{
if(key == GLFW_KEY_ESCAPE && action == GLFW_PRESS)
glfwSetWindowShouldClose(window, true);
}
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), index(index), initialized(false)
app(app), width(width), height(height), need_resize_refresh(false), iconified(false), index(index), initialized(false)
{
std::cout << "Creating a GlWindow" << std::endl;
if constexpr(uui::GlApplication::debug_mode)
std::cout << "Creating a GlWindow" << std::endl;
this->title = title;
}
uui::GlWindow::~GlWindow()
{
std::cout << "Closing a GlWindow" << std::endl;
if constexpr(uui::GlApplication::debug_mode)
std::cout << "Closing a GlWindow" << std::endl;
if(initialized)
{
std::cout << "Destructor-deinit a GlWindow" << std::endl;
if constexpr(uui::GlApplication::debug_mode)
std::cout << "Destructor-deinit a GlWindow" << std::endl;
deinit();
}
}
@ -97,10 +110,15 @@ void uui::GlWindow::init()
glfwSetWindowUserPointer(glfw_window, this);
glfwSetFramebufferSizeCallback(glfw_window, glfw_resize_callback);
glfwSetKeyCallback(glfw_window, glfw_key_callback);
glfwSetWindowIconifyCallback(glfw_window, glfw_iconify_callback);
if(!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress))
throw std::runtime_error("GLWindow : Failed to initialize OpenGL context");
// glEnable(GL_CULL_FACE);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
if constexpr(uui::GlApplication::debug_mode)
{
GLint flags;
@ -178,6 +196,13 @@ void uui::GlWindow::init()
}
glDeleteShader(vertex_shader);
glDeleteShader(fragment_shader);
font_manager.init();
glUseProgram(font_manager.gl_program);
glm::mat4 projection = glm::ortho(0.0f, static_cast<float>(width), 0.0f, static_cast<float>(height));
glUniformMatrix4fv(glGetUniformLocation(font_manager.gl_program, "projection"), 1, GL_FALSE, glm::value_ptr(projection));
glUseProgram(gl_program);
initialized = true;
}
@ -186,12 +211,14 @@ void uui::GlWindow::deinit()
if(!initialized)
throw std::runtime_error("GlWindow error : calling deinit while not initialized");
std::cout << "Deinit a GlWindow" << std::endl;
if constexpr(uui::GlApplication::debug_mode)
std::cout << "Deinit a GlWindow" << std::endl;
glfwMakeContextCurrent(glfw_window);
glDeleteProgram(gl_program);
for(auto& component: components) component->deinit();
components.clear();
font_manager.deinit();
glfwDestroyWindow(glfw_window);
initialized = false;
@ -199,17 +226,20 @@ void uui::GlWindow::deinit()
void uui::GlWindow::draw()
{
glfwMakeContextCurrent(glfw_window);
glClearColor(0.1f, 0.1f, 0.1f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
glUseProgram(gl_program);
if(need_resize_refresh)
if(!iconified)
{
for(auto& component: components) component->on_resize();
need_resize_refresh = false;
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->render();
glfwSwapBuffers(glfw_window);
}
@ -227,3 +257,17 @@ std::shared_ptr<uui::GlComponent> uui::GlWindow::create_component(
components.push_back(component);
return component;
}
std::shared_ptr<uui::GlLabel> uui::GlWindow::create_label(
const std::variant<int, float> x, const std::variant<int, float> y, const std::string& text,
const std::tuple<float, float, float, float>& text_color)
{
if(!initialized)
throw std::runtime_error("GlWindow error : cannot create component while not initialized");
glfwMakeContextCurrent(glfw_window);
std::shared_ptr<uui::GlLabel> label(new uui::GlLabel(app->get_window(index), x, y, text, text_color));
label->init();
components.push_back(label);
return label;
}