#include "pch.h" #include "log.h" #include "font.h" #include "shader.h" #include "asset.h" std::map FontManager::m_fonts; Sampler FontManager::m_sampler; bool Font::load(const char* ttf, int font_size) { Asset file; LOG("Font::load %s", ttf); if (file.open(ttf) && file.read_all()) { LOG("Font::load loaded"); auto bitmap = std::make_unique(w*h); chars.resize(num_chars); stbtt_BakeFontBitmap(file.m_data, 0, (float)font_size, bitmap.get(), w, h, start_char, num_chars, chars.data()); font_tex.create(w, h, GL_R8, GL_RED, bitmap.get()); file.close(); return true; } return false; } void FontManager::init() { m_sampler.create(); } bool FontManager::load(kFont id, const char* ttf, int sz) { return m_fonts[id].load(ttf, sz); } const Font& FontManager::get(kFont id) { return m_fonts[id]; } bool TextMesh::create() { glGenBuffers(2, font_buffers); #if USE_VBO glGenVertexArrays(1, &font_array); glBindVertexArray(font_array); glEnableVertexAttribArray(0); glEnableVertexAttribArray(1); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, font_buffers[1]); glBindBuffer(GL_ARRAY_BUFFER, font_buffers[0]); glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(glm::vec4), (GLvoid*)0); glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof(glm::vec4), (GLvoid*)(sizeof(float)*2)); glBindVertexArray(0); #endif // USE_VBO return true; } void TextMesh::update(kFont id, const char* text) { font_id = id; auto& f = FontManager::get(id); if (f.chars.size()) { const auto len = strlen(text); float x = 0; float y = 0; std::vector v; std::vector idx; glm::vec2 bbmin; glm::vec2 bbmax; for (int i = 0; i < len; i++) { int c = text[i] - f.start_char; stbtt_aligned_quad q; stbtt_GetBakedQuad((stbtt_bakedchar*)f.chars.data(), f.w, f.h, c, &x, &y, &q, true); auto n = (int)v.size(); v.emplace_back(q.x0, q.y1, q.s0, q.t1); v.emplace_back(q.x0, q.y0, q.s0, q.t0); v.emplace_back(q.x1, q.y0, q.s1, q.t0); v.emplace_back(q.x1, q.y1, q.s1, q.t1); idx.push_back(n+0); idx.push_back(n+1); idx.push_back(n+2); idx.push_back(n+0); idx.push_back(n+2); idx.push_back(n+3); bbmin = glm::min(bbmin, { q.x0, q.y0 }); bbmax = glm::max(bbmax, { q.x1, q.y1 }); } for (int i = 0; i < len*4; i++) { v[i] -= glm::vec4(bbmin, 0, 0); } bb = bbmax - bbmin; font_array_count = (int)idx.size(); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, font_buffers[1]); glBufferData(GL_ELEMENT_ARRAY_BUFFER, idx.size() * sizeof(GLushort), idx.data(), GL_STATIC_DRAW); glBindBuffer(GL_ARRAY_BUFFER, font_buffers[0]); glBufferData(GL_ARRAY_BUFFER, v.size() * sizeof(glm::vec4), v.data(), GL_STATIC_DRAW); glBindBuffer(GL_ARRAY_BUFFER, 0); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); } } void TextMesh::draw() { auto& f = FontManager::get(font_id); if (f.font_tex.ready()) { glActiveTexture(GL_TEXTURE0); f.font_tex.bind(); FontManager::m_sampler.bind(0); #if USE_VBO glBindVertexArray(font_array); glDrawElements(GL_TRIANGLES, font_array_count, GL_UNSIGNED_SHORT, 0); glBindVertexArray(0); #else glEnableVertexAttribArray(0); glEnableVertexAttribArray(1); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, font_buffers[1]); glBindBuffer(GL_ARRAY_BUFFER, font_buffers[0]); glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(glm::vec4), (GLvoid*)0); glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof(glm::vec4), (GLvoid*)(sizeof(float) * 2)); glDrawElements(GL_TRIANGLES, font_array_count, GL_UNSIGNED_SHORT, 0); glDisableVertexAttribArray(0); glDisableVertexAttribArray(1); glBindBuffer(GL_ARRAY_BUFFER, 0); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); #endif // USE_VBO f.font_tex.unbind(); FontManager::m_sampler.unbind(); } }