From 311c6758521ba88babbe3d3511b19941ea1880a5 Mon Sep 17 00:00:00 2001 From: zhenyan121 <3367366583@qq.com> Date: Thu, 16 Apr 2026 10:44:05 +0800 Subject: [PATCH] feat: add text class --- CMakeLists.txt | 1 + include/Cubed/renderer.hpp | 8 +++ include/Cubed/tools/font.hpp | 8 +-- include/Cubed/ui/color.hpp | 65 ++++++++++++++++++++++++ include/Cubed/ui/text.hpp | 46 +++++++++++++++++ src/renderer.cpp | 31 +++++++++--- src/shaders/text_v_shader.glsl | 4 +- src/tools/font.cpp | 39 ++++----------- src/ui/text.cpp | 90 ++++++++++++++++++++++++++++++++++ 9 files changed, 252 insertions(+), 40 deletions(-) create mode 100644 include/Cubed/ui/color.hpp create mode 100644 include/Cubed/ui/text.hpp create mode 100644 src/ui/text.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index d4c3a46..2f12f37 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -94,6 +94,7 @@ add_executable(${PROJECT_NAME} src/tools/font.cpp src/tools/log.cpp src/tools/perlin_noise.cpp + src/ui/text.cpp src/window.cpp ) diff --git a/include/Cubed/renderer.hpp b/include/Cubed/renderer.hpp index 4145e9b..6e82522 100644 --- a/include/Cubed/renderer.hpp +++ b/include/Cubed/renderer.hpp @@ -2,6 +2,7 @@ #include #include +#include #include #include @@ -45,6 +46,13 @@ private: std::unordered_map m_shaders; std::vector m_vao; std::vector m_ui; + + Text m_version_text; + Text m_fps_text; + Text m_player_pos_text; + + void init_text(); + void render_outline(); void render_sky(); void render_text(); diff --git a/include/Cubed/tools/font.hpp b/include/Cubed/tools/font.hpp index 60293be..796c9ec 100644 --- a/include/Cubed/tools/font.hpp +++ b/include/Cubed/tools/font.hpp @@ -8,6 +8,8 @@ #include #include +#include + struct Character { glm::vec2 uv_min; glm::vec2 uv_max; @@ -23,8 +25,8 @@ public: Font(); ~Font(); - static void render_text(const Shader& shader, const std::string& text, float x, float y, float scale, const glm::vec3& color); - + static std::vector vertices(const std::string& text, float x = 0.0f, float y = 0.0f, float scale = 1.0f); + static GLuint text_texture(); private: FT_Library m_ft; FT_Face m_face; @@ -32,7 +34,7 @@ private: float m_texture_width = 64; float m_texture_height = 64; - GLuint m_text_texture; + static inline GLuint m_text_texture; std::unordered_map m_characters; void load_character(char8_t c); diff --git a/include/Cubed/ui/color.hpp b/include/Cubed/ui/color.hpp new file mode 100644 index 0000000..d6fb03e --- /dev/null +++ b/include/Cubed/ui/color.hpp @@ -0,0 +1,65 @@ +#pragma once +#include +#include + +enum class Color { + BLACK, + WHITE, + RED, + GREEN, + BLUE, + YELLOW, + CYAN, + MAGENTA, + GRAY, + ORANGE, + PURPLE, + PINK, + BROWN +}; + +inline constexpr glm::vec4 color_value(Color color) { + using glm::vec4; + + switch (color) { + case Color::BLACK: + return vec4{0.0f, 0.0f, 0.0f, 1.0f}; + case Color::WHITE: + return vec4{1.0f, 1.0f, 1.0f, 1.0f}; + case Color::RED: + return vec4{1.0f, 0.0f, 0.0f, 1.0f}; + case Color::GREEN: + return vec4{0.0f, 1.0f, 0.0f, 1.0f}; + case Color::BLUE: + return vec4{0.0f, 0.0f, 1.0f, 1.0f}; + case Color::YELLOW: + return vec4{1.0f, 1.0f, 0.0f, 1.0f}; + case Color::CYAN: + return vec4{0.0f, 1.0f, 1.0f, 1.0f}; + case Color::MAGENTA: + return vec4{1.0f, 0.0f, 1.0f, 1.0f}; + case Color::GRAY: + return vec4{0.5f, 0.5f, 0.5f, 1.0f}; + case Color::ORANGE: + return vec4{1.0f, 0.647f, 0.0f, 1.0f}; + case Color::PURPLE: + return vec4{0.502f, 0.0f, 0.502f, 1.0f}; + case Color::PINK: + return vec4{1.0f, 0.753f, 0.769f, 1.0f}; + case Color::BROWN: + return vec4{0.647f, 0.165f, 0.165f, 1.0f}; + default: + CUBED_ASSERT_MSG(false, "Unknown Color"); + return vec4{1.0f, 1.0f, 1.0f, 1.0f}; + } + +} + +inline glm::vec4 rgb255_to_float(int r, int g, int b, int a) { + float nr = static_cast(r) / 255.0f; + float ng = static_cast(g) / 255.0f; + float nb = static_cast(b) / 255.0f; + float na = static_cast(a) / 255.0f; + + return glm::vec4{nr, ng, nb, na}; +} diff --git a/include/Cubed/ui/text.hpp b/include/Cubed/ui/text.hpp new file mode 100644 index 0000000..f340e61 --- /dev/null +++ b/include/Cubed/ui/text.hpp @@ -0,0 +1,46 @@ +#pragma once + +#include +#include +#include +#include + +#include +#include + +class Shader; + +class Text { +public: + Text(); + Text(std::string_view str, glm::vec2 pos = glm::vec2{0.0f, 0.0f}, Color color = Color::BLACK); + ~Text(); + + Text& color(Color color); + //Text& color(const glm::vec4& color, int pos); + Text& position(float x, float y); + Text& scale(float s); + static void set_loc(const Shader& shader); + Text& text(std::string_view str); + + + void render(); + +private: + float m_scale = 1.0f; + glm::vec2 m_pos{0.0f, 0.0f}; + + std::string m_name; + std::string m_text; + glm::vec4 m_color{1.0f, 1.0f, 1.0f, 1.0f}; + glm::mat4 m_model_matrix; + + std::vector m_vertices; + GLuint m_vbo = 0; + static inline GLuint m_color_loc = 0; + static inline GLuint m_mv_loc = 0; + + void update_vertices(); + void upload_to_gpu(); + +}; \ No newline at end of file diff --git a/src/renderer.cpp b/src/renderer.cpp index 7fd1029..f49024b 100644 --- a/src/renderer.cpp +++ b/src/renderer.cpp @@ -104,6 +104,8 @@ void Renderer::init() { glBindBuffer(GL_ARRAY_BUFFER, m_text_vbo); glBufferData(GL_ARRAY_BUFFER, sizeof(float)* 6 * 4, NULL, GL_DYNAMIC_DRAW); glBindBuffer(GL_ARRAY_BUFFER, 0); + + init_text(); } const Shader& Renderer::get_shader(const std::string& name) const { @@ -112,6 +114,23 @@ const Shader& Renderer::get_shader(const std::string& name) const { return it->second; } +void Renderer::init_text() { + const auto& shader = get_shader("text"); + Text::set_loc(shader); + m_version_text + .position(0.0f, 100.0f) + .scale(0.8f) + .color(Color::WHITE) + .text("Version: v0.0.1-Debug"); + m_fps_text + .position(0.0f, 50.0f) + .text("FPS: 0"); + m_player_pos_text + .position(0.0f, 150.0f) + .scale(0.8f) + .text("x: 0.00 y: 0.00 z: 0.00"); +} + void Renderer::render() { glClearColor(0.0, 0.0, 0.0, 1.0); glClear(GL_COLOR_BUFFER_BIT); @@ -192,15 +211,15 @@ void Renderer::render_text() { m_proj_loc = shader.loc("projection"); glUniformMatrix4fv(m_proj_loc, 1, GL_FALSE, glm::value_ptr(m_ui_proj)); - - Font::render_text(shader, std::string{"FPS: " + std::to_string(static_cast(App::get_fps()))}, 0.0f, 50.0f, 1.0f, glm::vec3(1.0f, 1.0f, 1.0f)); - - Font::render_text(shader, "Version: v0.0.1-Debug", 0.0f, 100.0f, 0.8f, glm::vec3(1.0f, 1.0f, 1.0f)); - + m_fps_text.text(std::string{"FPS: " + std::to_string(static_cast(App::get_fps()))}); const auto& player = m_world.get_player("TestPlayer"); const auto& pos = player.get_player_pos(); std::string player_pos = std::format("x: {:.2f} y: {:.2f} z: {:.2f}", pos.x, pos.y, pos.z); - Font::render_text(shader, player_pos, 0.0f, 150.0f, 0.8f, glm::vec3(1.0f, 1.0f, 1.0f)); + m_player_pos_text.text(player_pos); + + m_fps_text.render(); + m_player_pos_text.render(); + m_version_text.render(); glEnable(GL_DEPTH_TEST); } diff --git a/src/shaders/text_v_shader.glsl b/src/shaders/text_v_shader.glsl index d9d8d16..d0f09bc 100644 --- a/src/shaders/text_v_shader.glsl +++ b/src/shaders/text_v_shader.glsl @@ -7,9 +7,9 @@ layout (location = 2) in float layer; out vec2 tc; flat out int tex_layer; uniform mat4 projection; - +uniform mat4 mv_matrix; void main(void) { - gl_Position = projection * vec4(pos, 0.0, 1.0); + gl_Position = projection * mv_matrix * vec4(pos, 0.0, 1.0); tc = texCoord; tex_layer = int(layer); } \ No newline at end of file diff --git a/src/tools/font.cpp b/src/tools/font.cpp index 2f420ab..fd8b1db 100644 --- a/src/tools/font.cpp +++ b/src/tools/font.cpp @@ -1,12 +1,10 @@ -#include + #include #include #include #include - - Font::Font() { if (FT_Init_FreeType(&m_ft)) { @@ -24,9 +22,7 @@ Font::~Font() { FT_Done_Face(m_face); FT_Done_FreeType(m_ft); - for (const auto& [key, character] : m_characters) { - glDeleteTextures(1, &m_text_texture); - } + glDeleteTextures(1, &m_text_texture); } void Font::load_character(char8_t c) { @@ -36,6 +32,7 @@ void Font::load_character(char8_t c) { } const auto& width = m_face->glyph->bitmap.width; const auto& height = m_face->glyph->bitmap.rows; + glBindTexture(GL_TEXTURE_2D_ARRAY, m_text_texture); glTexSubImage3D( GL_TEXTURE_2D_ARRAY, 0, @@ -90,13 +87,9 @@ void Font::setup_font_character() { glBindTexture(GL_TEXTURE_2D_ARRAY, 0); } - - -void Font::render_text(const Shader& shader, const std::string& text, float x, float y, float scale, const glm::vec3& color) { +std::vector Font::vertices(const std::string &text, float x, float y, float scale) { static Font font; - - glUniform3f(shader.loc("textColor"), color.x, color.y, color.z); - glActiveTexture(GL_TEXTURE0); + std::vector vertices; for (char8_t c : text) { @@ -122,22 +115,10 @@ void Font::render_text(const Shader& shader, const std::string& text, float x, f x += (ch.advance >> 6) * scale; } - GLuint vbo; - glGenBuffers(1, &vbo); - glBindBuffer(GL_ARRAY_BUFFER, vbo); - glBufferData(GL_ARRAY_BUFFER, vertices.size() * sizeof(Vertex2D), vertices.data(), GL_STATIC_DRAW); - glBindTexture(GL_TEXTURE_2D_ARRAY, font.m_text_texture); - - glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex2D), (void*)0); - glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex2D), (void*)offsetof(Vertex2D, s)); - glVertexAttribPointer(2, 1, GL_FLOAT, GL_FALSE, sizeof(Vertex2D), (void*)offsetof(Vertex2D, layer)); - glEnableVertexAttribArray(0); - glEnableVertexAttribArray(1); - glEnableVertexAttribArray(2); - - glDrawArrays(GL_TRIANGLES, 0, vertices.size()); - glBindBuffer(GL_ARRAY_BUFFER, 0); - glBindTexture(GL_TEXTURE_2D_ARRAY, 0); - glDeleteBuffers(1, &vbo); + return vertices; } + +GLuint Font::text_texture() { + return m_text_texture; +} \ No newline at end of file diff --git a/src/ui/text.cpp b/src/ui/text.cpp new file mode 100644 index 0000000..9df9aaa --- /dev/null +++ b/src/ui/text.cpp @@ -0,0 +1,90 @@ +#include + +#include +#include + +#include +#include +Text::Text() { + +} + +Text::Text(std::string_view str, glm::vec2 pos, Color color) { + m_text.assign(str); + m_pos = pos; + m_color = color_value(color); + update_vertices(); +} + +Text::~Text() { + if (m_vbo != 0) { + glDeleteBuffers(1, &m_vbo); + } +} + +Text& Text::color(Color color) { + m_color = color_value(color); + return *this; +} + +Text& Text::position(float x, float y) { + m_pos = glm::vec2{x, y}; + return *this; +} + +Text& Text::scale(float s) { + m_scale = s; + return *this; +} + +void Text::set_loc(const Shader& shader) { + m_color_loc = shader.loc("textColor"); + m_mv_loc = shader.loc("mv_matrix"); +} + +Text& Text::text(std::string_view str) { + m_text.assign(str); + update_vertices(); + return *this; +} + +void Text::render() { + + CUBED_ASSERT_MSG(!m_vertices.empty(), "Text String Not Set"); + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D_ARRAY, Font::text_texture()); + CUBED_ASSERT_MSG(m_color_loc, "m_color_loc is null"); + + m_model_matrix = glm::translate(glm::mat4(1.0f), glm::vec3(m_pos.x, m_pos.y, 0.0f)) * + glm::scale(glm::mat4(1.0f), glm::vec3(m_scale, m_scale, 1.0f)); + + glUniform3f(m_color_loc, m_color.x, m_color.y, m_color.z); + glUniformMatrix4fv(m_mv_loc, 1, GL_FALSE, glm::value_ptr(m_model_matrix)); + glBindBuffer(GL_ARRAY_BUFFER, m_vbo); + + glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex2D), (void*)0); + glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex2D), (void*)offsetof(Vertex2D, s)); + glVertexAttribPointer(2, 1, GL_FLOAT, GL_FALSE, sizeof(Vertex2D), (void*)offsetof(Vertex2D, layer)); + + glEnableVertexAttribArray(0); + glEnableVertexAttribArray(1); + glEnableVertexAttribArray(2); + + glDrawArrays(GL_TRIANGLES, 0, m_vertices.size()); + glBindBuffer(GL_ARRAY_BUFFER, 0); + glBindTexture(GL_TEXTURE_2D_ARRAY, 0); +} + +void Text::update_vertices() { + m_vertices = Font::vertices(m_text); + upload_to_gpu(); +} + +void Text::upload_to_gpu() { + if (m_vbo == 0) { + glGenBuffers(1, &m_vbo); + } + CUBED_ASSERT_MSG(m_vbo, "Vbo Is Not Gen"); + glBindBuffer(GL_ARRAY_BUFFER, m_vbo); + glBufferData(GL_ARRAY_BUFFER, m_vertices.size() * sizeof(Vertex2D), m_vertices.data(), GL_DYNAMIC_DRAW); +} \ No newline at end of file