#include "text.hpp" #include #include #include #include #include #include "config.hpp" #include #include FT_FREETYPE_H void Text::render(const std::string& text, float x, float y, float scale, glm::vec3 color) { text_shader.use(); glm::mat4 projection = glm::ortho(0.0f, static_cast(SCR_WIDTH), 0.0f, static_cast(SCR_HEIGHT)); text_shader.setMat4("projection", projection); glUniform3f(glGetUniformLocation(text_shader.ID, "textColor"), color.x, color.y, color.z); glActiveTexture(GL_TEXTURE0); glBindVertexArray(text_vao); for(auto c : text) { auto& ch = characters.at(c); float xpos = x + ch.bearing.x * scale; float ypos = y - (ch.size.y - ch.bearing.y) * scale; float w = ch.size.x * scale; float h = ch.size.y * scale; float vertices[6][4] = { { xpos, ypos + h, 0.0f, 0.0f }, { xpos, ypos, 0.0f, 1.0f }, { xpos + w, ypos, 1.0f, 1.0f }, { xpos, ypos + h, 0.0f, 0.0f }, { xpos + w, ypos, 1.0f, 1.0f }, { xpos + w, ypos + h, 1.0f, 0.0f } }; // rander glyph texture over quad glBindTexture(GL_TEXTURE_2D, ch.texture_id); // update content of VBO memory glBindBuffer(GL_ARRAY_BUFFER, text_vbo); glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(vertices), vertices); glBindBuffer(GL_ARRAY_BUFFER, 0); // render quad glDrawArrays(GL_TRIANGLES, 0, 6); x += (ch.advance >> 6) * scale; } glBindVertexArray(0); glBindTexture(GL_TEXTURE_2D, 0); } void Text::load_font() { FT_Library ft; int fail = FT_Init_FreeType(&ft); dbc::check(fail == 0, "FreeType failed."); FT_Face face; fail = FT_New_Face(ft, font.c_str(), 0, &face); dbc::check(fail == 0, "Failed to load font."); // load the font bitmaps FT_Set_Pixel_Sizes(face, 0, 48); glPixelStorei(GL_UNPACK_ALIGNMENT, 1); for(unsigned char c = 0; c < 255; c++) { fail = FT_Load_Char(face, c, FT_LOAD_RENDER); dbc::check(fail == 0, $F("Failed to load char {}", int(c))); unsigned int texture = UINT_MAX; glGenTextures(1, &texture); glBindTexture(GL_TEXTURE_2D, texture); glTexImage2D( GL_TEXTURE_2D, 0, GL_RED, face->glyph->bitmap.width, face->glyph->bitmap.rows, 0, GL_RED, GL_UNSIGNED_BYTE, 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); characters.try_emplace(c, texture, glm::ivec2(face->glyph->bitmap.width, face->glyph->bitmap.rows), glm::ivec2(face->glyph->bitmap_left, face->glyph->bitmap_top), static_cast(face->glyph->advance.x)); } // unbind glBindTexture(GL_TEXTURE_2D, 0); // cleanup FT_Done_Face(face); FT_Done_FreeType(ft); // create teh vao/vbo glGenVertexArrays(1, &text_vao); glGenBuffers(1, &text_vbo); glBindVertexArray(text_vao); glBindBuffer(GL_ARRAY_BUFFER, text_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); glBindVertexArray(0); }