132 lines
4.7 KiB
C++
132 lines
4.7 KiB
C++
// Must be the first include
|
|
#include <glad/glad.h>
|
|
|
|
// Other includes
|
|
#include <GLFW/glfw3.h>
|
|
#include <glm/ext/matrix_clip_space.hpp>
|
|
#include <glm/gtc/type_ptr.hpp>
|
|
|
|
#include "Gedeng/Logger.h"
|
|
#include "Gedeng/TextLabel.h"
|
|
|
|
namespace Gedeng {
|
|
|
|
TextLabel::TextLabel(const String &text) : text(text), shader(Shader("Shader/text.vs", "Shader/text.fs")) {
|
|
FT_Library ft;
|
|
if (FT_Init_FreeType(&ft)) {
|
|
GG_CORE_ERROR("Couldn't create font library!");
|
|
return;
|
|
}
|
|
|
|
FT_Face face;
|
|
if (FT_New_Face(ft, "Resources/Fonts/Inter.ttf", 0, &face)) {
|
|
GG_CORE_ERROR("Couldn't load font from path!");
|
|
return;
|
|
}
|
|
|
|
// Set size
|
|
FT_Set_Pixel_Sizes(face, 0, 12);
|
|
|
|
// Load first 128 ASCII Characters
|
|
glPixelStorei(GL_UNPACK_ALIGNMENT, 1); // disable byte-alignment restriction
|
|
|
|
for (unsigned char c = 0; c < 128; c++) {
|
|
// load character glyph
|
|
if (FT_Load_Char(face, c, FT_LOAD_RENDER)) {
|
|
GG_CORE_ERROR("Couldn't load character glyph!");
|
|
continue;
|
|
}
|
|
// generate texture
|
|
unsigned int texture;
|
|
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);
|
|
// set texture options
|
|
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);
|
|
// now store character for later use
|
|
Character character = {texture, glm::ivec2(face->glyph->bitmap.width, face->glyph->bitmap.rows),
|
|
glm::ivec2(face->glyph->bitmap_left, face->glyph->bitmap_top),
|
|
static_cast<unsigned int>(face->glyph->advance.x)};
|
|
characters.insert(std::pair<char, Character>(c, character));
|
|
}
|
|
|
|
glBindTexture(GL_TEXTURE_2D, 0);
|
|
|
|
// destroy FreeType once we're finished
|
|
FT_Done_Face(face);
|
|
FT_Done_FreeType(ft);
|
|
|
|
// configure VAO/VBO for texture quads
|
|
// -----------------------------------
|
|
glGenVertexArrays(1, &vao);
|
|
glGenBuffers(1, &vbo);
|
|
glBindVertexArray(vao);
|
|
glBindBuffer(GL_ARRAY_BUFFER, 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);
|
|
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
|
glBindVertexArray(0);
|
|
|
|
valid = true;
|
|
}
|
|
|
|
void TextLabel::set_text(const String &text) {
|
|
this->text = text;
|
|
}
|
|
|
|
void TextLabel::render_text(float x, float y, float scale, Vector3 color) {
|
|
// activate corresponding render state
|
|
shader.use();
|
|
|
|
glUniform3f(glGetUniformLocation(shader.ID, "textColor"), color.x, color.y, color.z);
|
|
|
|
// FIXME: We need the screen size here... (or UI module size?)
|
|
glm::mat4 projection = glm::ortho(0.0f, static_cast<float>(900), 0.0f, static_cast<float>(600));
|
|
glUniformMatrix4fv(glGetUniformLocation(shader.ID, "projection"), 1, GL_FALSE, glm::value_ptr(projection));
|
|
|
|
glActiveTexture(GL_TEXTURE0);
|
|
glBindVertexArray(vao);
|
|
|
|
// iterate through all characters
|
|
for (size_t i = 0; i < text.get_length(); i++) {
|
|
Character ch = characters[text[i]];
|
|
|
|
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;
|
|
// update VBO for each character
|
|
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}};
|
|
// render glyph texture over quad
|
|
glBindTexture(GL_TEXTURE_2D, ch.texture_id);
|
|
// update content of VBO memory
|
|
glBindBuffer(GL_ARRAY_BUFFER, vbo);
|
|
glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(vertices),
|
|
vertices); // be sure to use glBufferSubData and not glBufferData
|
|
|
|
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
|
// render quad
|
|
glDrawArrays(GL_TRIANGLES, 0, 6);
|
|
// now advance cursors for next glyph (note that advance is number of 1/64 pixels)
|
|
x += (ch.advance >> 6) * scale; // bitshift by 6 to get value in pixels (2^6 = 64 (divide amount of 1/64th
|
|
// pixels by 64 to get amount of pixels))
|
|
}
|
|
|
|
glBindVertexArray(0);
|
|
glBindTexture(GL_TEXTURE_2D, 0);
|
|
}
|
|
|
|
bool TextLabel::is_valid() {
|
|
return valid;
|
|
}
|
|
|
|
} // namespace Gedeng
|