From 678414f0142e90976a0c93dcbd91fbcb7960c196 Mon Sep 17 00:00:00 2001 From: Phireh Date: Sat, 6 Jan 2024 13:16:00 +0100 Subject: [PATCH] Refactor text rendering to use less input data --- main.cpp | 89 +++++++++++++++++++++++++++-------------------- shaders/text.vert | 8 +++-- 2 files changed, 57 insertions(+), 40 deletions(-) diff --git a/main.cpp b/main.cpp index 2019272..1b183ed 100644 --- a/main.cpp +++ b/main.cpp @@ -61,7 +61,7 @@ struct debug_clock_t struct timespec spec; clock_gettime(CLOCK_MONOTONIC, &spec); start = spec.tv_sec * 1000 * 1000 + spec.tv_nsec / 1000; - + } ~debug_clock_t() { @@ -207,7 +207,7 @@ uint32_t make_gl_program(const char *pathname_vertex, const char *pathname_fragm char *vertex_source = load_file(pathname_vertex); char *fragment_source = load_file(pathname_fragment); - + unsigned int vertex_shader = build_shader_from_source(vertex_source, GL_VERTEX_SHADER); unsigned int fragment_shader = build_shader_from_source(fragment_source, GL_FRAGMENT_SHADER); @@ -237,9 +237,9 @@ uint32_t make_gl_program(const char *pathname_vertex, const char *pathname_fragm void render_text(const char *text, float x, float y, float scale, glm::vec3 color) { // TODO: Group draw calls together instead of doing 1 draw call/character. Use an atlas with GL_TEXTURE_ARRAY - // TODO: Do not make draw calls for invisible characters! - - // activate corresponding render state + // Take tips from https://www.youtube.com/watch?v=S0PyZKX4lyI + + // activate corresponding render state glUseProgram(text_program); glUniform3f(glGetUniformLocation(text_program, "text_color"), color.x, color.y, color.z); glActiveTexture(GL_TEXTURE0); @@ -251,31 +251,39 @@ void render_text(const char *text, float x, float y, float scale, glm::vec3 colo char c = *p; charglyph_t charglyph = glyphmap[(size_t)c]; + if (c == ' ') // Just advance by normal horizontal distance and prepare for next char + { + x += (charglyph.advance >> 6) * scale; + continue; + } + float xpos = x + charglyph.bearing.x * scale; float ypos = y - (charglyph.size.y - charglyph.bearing.y) * scale; - float w = charglyph.size.x * scale; - float h = charglyph.size.y * scale; + glm::mat4 transform = glm::translate(glm::mat4(1.0f), glm::vec3(xpos, ypos, 0)) * glm::scale(glm::mat4(1.0f), glm::vec3(charglyph.size.x * scale, charglyph.size.y * scale, 0)); + glUniformMatrix4fv(glGetUniformLocation(text_program, "transform"), 1, GL_FALSE, &transform[0][0]); + // update VBO for each character - float vertices[4][4] = { - { xpos, ypos + h, 0.0f, 0.0f }, - { xpos, ypos, 0.0f, 1.0f }, - { xpos + w, ypos, 1.0f, 1.0f }, - { xpos + w, ypos + h, 1.0f, 0.0f } - }; + // float vertices[4][4] = { + // { xpos, ypos + h, 0.0f, 0.0f }, + // { xpos, ypos, 0.0f, 1.0f }, + // { xpos + w, ypos, 1.0f, 1.0f }, + // { xpos + w, ypos + h, 1.0f, 0.0f } + // }; // render glyph texture over quad glBindTexture(GL_TEXTURE_2D, charglyph.tex); // update content of VBO memory glBindBuffer(GL_ARRAY_BUFFER, textvbo); - glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(vertices), vertices); - glBindBuffer(GL_ARRAY_BUFFER, 0); + //glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(vertices), vertices); + // render quad glEnable(GL_CULL_FACE); - glDrawArrays(GL_TRIANGLE_FAN, 0, 4); + glDrawArraysInstanced(GL_TRIANGLE_FAN, 0, 4, 1); glDisable(GL_CULL_FACE); // now advance cursors for next glyph (note that advance is number of 1/64 pixels) x += (charglyph.advance >> 6) * scale; // bitshift by 6 to get value in pixels (2^6 = 64) } + glBindBuffer(GL_ARRAY_BUFFER, 0); glBindVertexArray(0); glBindTexture(GL_TEXTURE_2D, 0); } @@ -297,7 +305,7 @@ void create_grid(grid_t *grid, int rows, int columns) { grid->rows = rows; grid->columns = columns; - if (!grid->hexes) + if (!grid->hexes) grid->hexes = (hex_t*)calloc(grid->rows * grid->columns, sizeof(hex_t)); else { @@ -329,13 +337,13 @@ void create_grid(grid_t *grid, int rows, int columns) the_hexagon->vertices[4] = the_hexagon->position + glm::vec3(radius, 0, 0); the_hexagon->vertices[5] = the_hexagon->position + glm::vec3(radius * glm::cos(glm::radians(60.0)), -radius * glm::sin(glm::radians(60.0)), 0); the_hexagon->vertices[6] = the_hexagon->position + glm::vec3(-radius * glm::cos(glm::radians(60.0)), -radius * glm::sin(glm::radians(60.0)), 0); - + glGenVertexArrays(1, &the_hexagon->vao); glGenBuffers(1, &the_hexagon->vbo); glBindVertexArray(the_hexagon->vao); glBindBuffer(GL_ARRAY_BUFFER, the_hexagon->vbo); glBufferData(GL_ARRAY_BUFFER, sizeof(float) * 7 * 3, the_hexagon->vertices, GL_STATIC_DRAW); - + // EBO setup unsigned int indices[18]; indices[0] = 0; indices[1] = 2; indices[2] = 1; @@ -348,7 +356,7 @@ void create_grid(grid_t *grid, int rows, int columns) glGenBuffers(1, &the_hexagon->ebo); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, the_hexagon->ebo); glBufferData(GL_ELEMENT_ARRAY_BUFFER, 6*3 * sizeof(unsigned int), indices, GL_STATIC_DRAW); - + glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, (void*)0); glEnableVertexAttribArray(0); glBindBuffer(GL_ARRAY_BUFFER, 0); @@ -408,10 +416,10 @@ int main([[maybe_unused]]int argc, [[maybe_unused]]char **argv) FT_Set_Pixel_Sizes(face, 0, 48); glPixelStorei(GL_UNPACK_ALIGNMENT, 1); // disable byte-alignment restriction - + for (unsigned char c = 0; c < 128; c++) { - // load character glyph + // load character glyph if (FT_Load_Char(face, c, FT_LOAD_RENDER)) { MAIN_ERROR(ERR_CHAR_LOAD); @@ -438,7 +446,7 @@ int main([[maybe_unused]]int argc, [[maybe_unused]]char **argv) glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); // now store character for later use charglyph_t charglyph = { - texture, + texture, glm::ivec2(face->glyph->bitmap.width, face->glyph->bitmap.rows), glm::ivec2(face->glyph->bitmap_left, face->glyph->bitmap_top), (uint32_t)face->glyph->advance.x @@ -452,14 +460,21 @@ int main([[maybe_unused]]int argc, [[maybe_unused]]char **argv) // text initialization text_program = make_gl_program("shaders/text.vert", "shaders/text.frag"); - + static GLfloat vertex_data[] = { + 0.0f, 1.0f, + 0.0f, 0.0f, + 1.0f, 0.0f, + 1.0f, 1.0f, + }; + + glGenVertexArrays(1, &textvao); glGenBuffers(1, &textvbo); glBindVertexArray(textvao); glBindBuffer(GL_ARRAY_BUFFER, textvbo); - glBufferData(GL_ARRAY_BUFFER, sizeof(float) * 6 * 4, NULL, GL_DYNAMIC_DRAW); + glBufferData(GL_ARRAY_BUFFER, sizeof(vertex_data), vertex_data, GL_STATIC_DRAW); glEnableVertexAttribArray(0); - glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 4 * sizeof(float), 0); + glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, 0); glBindBuffer(GL_ARRAY_BUFFER, 0); glBindVertexArray(0); @@ -477,7 +492,7 @@ int main([[maybe_unused]]int argc, [[maybe_unused]]char **argv) ImGui::StyleColorsDark(); ImGui_ImplGlfw_InitForOpenGL(window, true); ImGui_ImplOpenGL3_Init("#version 330 core"); // same as shader version - + double cursor_x; double cursor_y; camera_t the_camera; @@ -487,7 +502,7 @@ int main([[maybe_unused]]int argc, [[maybe_unused]]char **argv) static selection_t selection; selection.indices = (int32_t*)calloc(1, sizeof(int32_t) * grid.rows * grid.columns); selection.nselected = 0; - + the_camera.position = glm::vec3(0.0f, 0.0f, 1.0f); the_camera.size = glm::vec2(1.0f, 1.0f); // main loop @@ -538,7 +553,7 @@ int main([[maybe_unused]]int argc, [[maybe_unused]]char **argv) cursor_dy = cursor_y; glfwGetCursorPos(window, &cursor_x, &cursor_y); - + cursor_dx -= cursor_x; cursor_dy -= cursor_y; @@ -574,7 +589,7 @@ int main([[maybe_unused]]int argc, [[maybe_unused]]char **argv) proj_matrix = glm::ortho((the_camera.position.x - the_camera.size.x/2) * aspect_ratio, (the_camera.position.x + the_camera.size.x/2) * aspect_ratio, the_camera.position.y - the_camera.size.y/2, the_camera.position.y + the_camera.size.y/2); glm::vec4 aux((float)cursor_x, (float)cursor_y, 0.0f, 1.0f); - + // move screen coordinates to NDC aux.x -= window_width/2.0f; aux.x /= window_width/2.0f; @@ -582,7 +597,7 @@ int main([[maybe_unused]]int argc, [[maybe_unused]]char **argv) aux.y /= -window_height/2.0f; aux = glm::inverse(proj_matrix) * aux; cursor_world = glm::vec2(aux.x, aux.y); - + glUseProgram(hex_program); glUniformMatrix4fv(glGetUniformLocation(hex_program, "model"), 1, GL_FALSE, &model_matrix[0][0]); glUniformMatrix4fv(glGetUniformLocation(hex_program, "view"), 1, GL_FALSE, &view_matrix[0][0]); @@ -612,7 +627,7 @@ int main([[maybe_unused]]int argc, [[maybe_unused]]char **argv) else glUniform4f(glGetUniformLocation(hex_program, "hex_color"), grid.hexes[idx].color.x, grid.hexes[idx].color.y, grid.hexes[idx].color.z, grid.hexes[idx].color.w); } - + glBindVertexArray(grid.hexes[idx].vao); glBindBuffer(GL_ARRAY_BUFFER, grid.hexes[idx].vbo); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, grid.hexes[idx].ebo); @@ -660,18 +675,18 @@ int main([[maybe_unused]]int argc, [[maybe_unused]]char **argv) render_text(buf, 25.0f, window_height - 25.0f, .5f, glm::vec3(1.0f, 1.0f, 1.0f)); } } - + glDisable(GL_BLEND); glfwPollEvents(); static int grid_rows = grid.rows; static int grid_columns = grid.columns; - + if (grid_rows != grid.rows || grid_columns != grid.columns) { create_grid(&grid, grid_rows, grid_columns); } - + // Start the Dear ImGui frame { TIME_BLOCK(gui_render); @@ -693,7 +708,7 @@ int main([[maybe_unused]]int argc, [[maybe_unused]]char **argv) ImGui::Render(); ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData()); } - + glfwSwapBuffers(window); } @@ -701,7 +716,7 @@ int main([[maybe_unused]]int argc, [[maybe_unused]]char **argv) ImGui_ImplOpenGL3_Shutdown(); ImGui_ImplGlfw_Shutdown(); ImGui::DestroyContext(); - + return 0; exit_main_with_error: if (window) diff --git a/shaders/text.vert b/shaders/text.vert index 3ea62c3..49c10a1 100644 --- a/shaders/text.vert +++ b/shaders/text.vert @@ -1,11 +1,13 @@ #version 330 core -layout (location = 0) in vec4 vertex; // +layout (location = 0) in vec2 vertex; // out vec2 texuv; +uniform mat4 transform; uniform mat4 projection; void main() { - gl_Position = projection * vec4(vertex.xy, 0.0, 1.0); - texuv = vertex.zw; + gl_Position = projection * transform * vec4(vertex.xy, 0.0, 1.0); + texuv = vertex.xy; + texuv.y=1.0f-texuv.y; }