mirror of
https://github.com/zhenyan121/Cubed.git
synced 2026-04-10 06:14:07 +08:00
perf: optimize text rendering performance
This commit is contained in:
@@ -8,7 +8,7 @@ constexpr int MAX_UI_NUM = 1;
|
|||||||
constexpr int CHUCK_SIZE = 16;
|
constexpr int CHUCK_SIZE = 16;
|
||||||
constexpr int DISTANCE = 8;
|
constexpr int DISTANCE = 8;
|
||||||
constexpr int MAX_BLOCK_STATUS = 1;
|
constexpr int MAX_BLOCK_STATUS = 1;
|
||||||
|
constexpr int MAX_CHARACTER = 128;
|
||||||
constexpr float FOV = 70.0f;
|
constexpr float FOV = 70.0f;
|
||||||
|
|
||||||
constexpr float VERTICES_POS[6][6][3] = {
|
constexpr float VERTICES_POS[6][6][3] = {
|
||||||
|
|||||||
@@ -9,7 +9,8 @@
|
|||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
|
|
||||||
struct Character {
|
struct Character {
|
||||||
GLuint texture_id;
|
glm::vec2 uv_min;
|
||||||
|
glm::vec2 uv_max;
|
||||||
glm::ivec2 size;
|
glm::ivec2 size;
|
||||||
glm::ivec2 bearing;
|
glm::ivec2 bearing;
|
||||||
GLuint advance;
|
GLuint advance;
|
||||||
@@ -20,12 +21,16 @@ public:
|
|||||||
Font();
|
Font();
|
||||||
~Font();
|
~Font();
|
||||||
|
|
||||||
static void render_text(GLuint program, GLuint vbo, const std::string& text, float x, float y, float scale, const glm::vec3& color);
|
static void render_text(GLuint program, const std::string& text, float x, float y, float scale, const glm::vec3& color);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
FT_Library m_ft;
|
FT_Library m_ft;
|
||||||
FT_Face m_face;
|
FT_Face m_face;
|
||||||
|
|
||||||
|
float m_texture_width = 64;
|
||||||
|
float m_texture_height = 64;
|
||||||
|
|
||||||
|
GLuint m_text_texture;
|
||||||
std::unordered_map<char8_t, Character> m_characters;
|
std::unordered_map<char8_t, Character> m_characters;
|
||||||
|
|
||||||
void load_character(char8_t c);
|
void load_character(char8_t c);
|
||||||
|
|||||||
@@ -187,7 +187,8 @@ void Renderer::render_text() {
|
|||||||
m_proj_loc = glGetUniformLocation(m_text_program, "projection");
|
m_proj_loc = glGetUniformLocation(m_text_program, "projection");
|
||||||
|
|
||||||
glUniformMatrix4fv(m_proj_loc, 1, GL_FALSE, glm::value_ptr(m_ui_proj));
|
glUniformMatrix4fv(m_proj_loc, 1, GL_FALSE, glm::value_ptr(m_ui_proj));
|
||||||
Font::render_text(m_text_program, m_text_vbo, std::string{"fps" + std::to_string(static_cast<int>(App::get_fps()))}, 0.0f, 50.0f, 1.0f, glm::vec3(1.0f, 1.0f, 1.0f));
|
Font::render_text(m_text_program, std::string{"FPS: " + std::to_string(static_cast<int>(App::get_fps()))}, 0.0f, 50.0f, 1.0f, glm::vec3(1.0f, 1.0f, 1.0f));
|
||||||
|
Font::render_text(m_text_program, "Version: v0.0.1-Debug", 0.0f, 100.0f, 0.8f, glm::vec3(1.0f, 1.0f, 1.0f));
|
||||||
glEnable(GL_DEPTH_TEST);
|
glEnable(GL_DEPTH_TEST);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,12 +1,14 @@
|
|||||||
#version 460
|
#version 460
|
||||||
|
|
||||||
in vec2 texCoord;
|
in vec2 tc;
|
||||||
out vec4 color;
|
flat in int tex_layer;
|
||||||
|
|
||||||
layout (binding = 0) uniform sampler2D text;
|
layout (binding = 0) uniform sampler2DArray text;
|
||||||
uniform vec3 textColor;
|
uniform vec3 textColor;
|
||||||
|
|
||||||
|
out vec4 color;
|
||||||
|
|
||||||
void main(void) {
|
void main(void) {
|
||||||
vec4 smapled = vec4(1.0, 1.0, 1.0, texture(text, texCoord).r);
|
vec4 smapled = vec4(1.0, 1.0, 1.0, texture(text, vec3(tc, tex_layer)).r);
|
||||||
color = vec4(textColor, 1.0) * smapled;
|
color = vec4(textColor, 1.0) * smapled;
|
||||||
}
|
}
|
||||||
@@ -1,11 +1,15 @@
|
|||||||
#version 460
|
#version 460
|
||||||
|
|
||||||
layout (location = 0) in vec4 vertex;
|
layout (location = 0) in vec2 pos;
|
||||||
out vec2 texCoord;
|
layout (location = 1) in vec2 texCoord;
|
||||||
|
layout (location = 2) in float layer;
|
||||||
|
|
||||||
|
out vec2 tc;
|
||||||
|
flat out int tex_layer;
|
||||||
uniform mat4 projection;
|
uniform mat4 projection;
|
||||||
|
|
||||||
void main(void) {
|
void main(void) {
|
||||||
gl_Position = projection * vec4(vertex.xy, 0.0, 1.0);
|
gl_Position = projection * vec4(pos, 0.0, 1.0);
|
||||||
texCoord = vec2(vertex.zw);
|
tc = texCoord;
|
||||||
|
tex_layer = int(layer);
|
||||||
}
|
}
|
||||||
@@ -1,5 +1,4 @@
|
|||||||
|
#include <Cubed/config.hpp>
|
||||||
|
|
||||||
#include <Cubed/tools/font.hpp>
|
#include <Cubed/tools/font.hpp>
|
||||||
#include <Cubed/tools/log.hpp>
|
#include <Cubed/tools/log.hpp>
|
||||||
|
|
||||||
@@ -24,7 +23,7 @@ Font::~Font() {
|
|||||||
FT_Done_Face(m_face);
|
FT_Done_Face(m_face);
|
||||||
FT_Done_FreeType(m_ft);
|
FT_Done_FreeType(m_ft);
|
||||||
for (const auto& [key, character] : m_characters) {
|
for (const auto& [key, character] : m_characters) {
|
||||||
glDeleteTextures(1, &character.texture_id);
|
glDeleteTextures(1, &m_text_texture);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -33,27 +32,25 @@ void Font::load_character(char8_t c) {
|
|||||||
LOG::error("FREETYTPE: Failed to load Glyph");
|
LOG::error("FREETYTPE: Failed to load Glyph");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
GLuint texture;
|
const auto& width = m_face->glyph->bitmap.width;
|
||||||
glGenTextures(1, &texture);
|
const auto& height = m_face->glyph->bitmap.rows;
|
||||||
glBindTexture(GL_TEXTURE_2D, texture);
|
glTexSubImage3D(
|
||||||
glTexImage2D(
|
GL_TEXTURE_2D_ARRAY,
|
||||||
GL_TEXTURE_2D,
|
|
||||||
0,
|
0,
|
||||||
GL_RED,
|
|
||||||
m_face->glyph->bitmap.width,
|
|
||||||
m_face->glyph->bitmap.rows,
|
|
||||||
0,
|
0,
|
||||||
|
0,
|
||||||
|
static_cast<int>(c),
|
||||||
|
width,
|
||||||
|
height,
|
||||||
|
1,
|
||||||
GL_RED,
|
GL_RED,
|
||||||
GL_UNSIGNED_BYTE,
|
GL_UNSIGNED_BYTE,
|
||||||
m_face->glyph->bitmap.buffer
|
m_face->glyph->bitmap.buffer
|
||||||
);
|
);
|
||||||
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);
|
|
||||||
|
|
||||||
Character character = {
|
Character character = {
|
||||||
texture,
|
glm::vec2{0.0f, 0.0f},
|
||||||
|
glm::vec2{static_cast<float>(width) / m_texture_width, static_cast<float>(height) / m_texture_height},
|
||||||
glm::ivec2(m_face->glyph->bitmap.width, m_face->glyph->bitmap.rows),
|
glm::ivec2(m_face->glyph->bitmap.width, m_face->glyph->bitmap.rows),
|
||||||
glm::ivec2(m_face->glyph->bitmap_left, m_face->glyph->bitmap_top),
|
glm::ivec2(m_face->glyph->bitmap_left, m_face->glyph->bitmap_top),
|
||||||
static_cast<GLuint>(m_face->glyph->advance.x)
|
static_cast<GLuint>(m_face->glyph->advance.x)
|
||||||
@@ -63,19 +60,44 @@ void Font::load_character(char8_t c) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Font::setup_font_character() {
|
void Font::setup_font_character() {
|
||||||
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
|
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
|
||||||
|
|
||||||
|
glGenTextures(1, &m_text_texture);
|
||||||
|
glBindTexture(GL_TEXTURE_2D_ARRAY, m_text_texture);
|
||||||
|
glTexImage3D(
|
||||||
|
GL_TEXTURE_2D_ARRAY,
|
||||||
|
0,
|
||||||
|
GL_RED,
|
||||||
|
m_texture_width,
|
||||||
|
m_texture_height,
|
||||||
|
MAX_CHARACTER,
|
||||||
|
0,
|
||||||
|
GL_RED,
|
||||||
|
GL_UNSIGNED_BYTE,
|
||||||
|
nullptr
|
||||||
|
);
|
||||||
|
|
||||||
for (char8_t c = 0; c < 128; c++) {
|
for (char8_t c = 0; c < 128; c++) {
|
||||||
load_character(c);
|
load_character(c);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||||
|
glBindTexture(GL_TEXTURE_2D_ARRAY, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void Font::render_text(GLuint program, GLuint vbo, const std::string& text, float x, float y, float scale, const glm::vec3& color) {
|
void Font::render_text(GLuint program, const std::string& text, float x, float y, float scale, const glm::vec3& color) {
|
||||||
static Font font;
|
static Font font;
|
||||||
glUseProgram(program);
|
glUseProgram(program);
|
||||||
glUniform3f(glGetUniformLocation(program, "textColor"), color.x, color.y, color.z);
|
glUniform3f(glGetUniformLocation(program, "textColor"), color.x, color.y, color.z);
|
||||||
glActiveTexture(GL_TEXTURE0);
|
glActiveTexture(GL_TEXTURE0);
|
||||||
|
|
||||||
|
std::vector<Vertex2D> vertices;
|
||||||
|
|
||||||
for (char8_t c : text) {
|
for (char8_t c : text) {
|
||||||
auto it = font.m_characters.find(c);
|
auto it = font.m_characters.find(c);
|
||||||
if (it == font.m_characters.end()) {
|
if (it == font.m_characters.end()) {
|
||||||
@@ -89,24 +111,32 @@ void Font::render_text(GLuint program, GLuint vbo, const std::string& text, floa
|
|||||||
float w = ch.size.x * scale;
|
float w = ch.size.x * scale;
|
||||||
float h = ch.size.y * scale;
|
float h = ch.size.y * scale;
|
||||||
|
|
||||||
float vertices[6][4] {
|
vertices.emplace_back(xpos, ypos + h, ch.uv_min.x, ch.uv_max.y, static_cast<float>(c));
|
||||||
{ xpos, ypos + h, 0.0, 1.0 },
|
vertices.emplace_back(xpos, ypos, ch.uv_min.x, ch.uv_min.y, static_cast<float>(c));
|
||||||
{ xpos, ypos, 0.0, 0.0 },
|
vertices.emplace_back(xpos + w, ypos, ch.uv_max.x, ch.uv_min.y, static_cast<float>(c));
|
||||||
{ xpos + w, ypos, 1.0, 0.0 },
|
vertices.emplace_back(xpos, ypos + h, ch.uv_min.x, ch.uv_max.y, static_cast<float>(c));
|
||||||
|
vertices.emplace_back(xpos + w, ypos, ch.uv_max.x, ch.uv_min.y, static_cast<float>(c));
|
||||||
{ xpos, ypos + h, 0.0, 1.0 },
|
vertices.emplace_back(xpos + w, ypos + h, ch.uv_max.x, ch.uv_max.y, static_cast<float>(c));
|
||||||
{ xpos + w, ypos, 1.0, 0.0 },
|
|
||||||
{ xpos + w, ypos + h, 1.0, 1.0 }
|
|
||||||
};
|
|
||||||
glBindTexture(GL_TEXTURE_2D, ch.texture_id);
|
|
||||||
glBindBuffer(GL_ARRAY_BUFFER, vbo);
|
|
||||||
glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(vertices), vertices);
|
|
||||||
glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 4 * sizeof(GLfloat), 0);
|
|
||||||
glEnableVertexAttribArray(0);
|
|
||||||
glDrawArrays(GL_TRIANGLES, 0, 6);
|
|
||||||
x += (ch.advance >> 6) * scale;
|
x += (ch.advance >> 6) * scale;
|
||||||
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
|
||||||
}
|
}
|
||||||
glBindTexture(GL_TEXTURE_2D, 0);
|
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() * 6);
|
||||||
|
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||||
|
glBindTexture(GL_TEXTURE_2D_ARRAY, 0);
|
||||||
|
glDeleteBuffers(1, &vbo);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user