Add draft for text rendering

This commit is contained in:
karl 2021-05-04 12:07:56 +02:00
parent 307d000253
commit 10138d5fd8
6 changed files with 187 additions and 2 deletions

View File

@ -19,7 +19,7 @@ env = Environment(tools=['default', 'compilation_db'])
env.CompilationDatabase() env.CompilationDatabase()
env.Append(CPPPATH=['cpp/', 'include/']) env.Append(CPPPATH=['cpp/', 'include/'])
env.Append(LIBS=['glfw', 'dl']) env.Append(LIBS=['glfw', 'dl', 'freetype'])
add_third_party_includes(env) add_third_party_includes(env)
add_strict_compile_flags(env) add_strict_compile_flags(env)

View File

@ -15,6 +15,11 @@ void RenderBackend::initialize_window(unsigned int width, unsigned int height, S
window = glfwCreateWindow(width, height, title, NULL, NULL); window = glfwCreateWindow(width, height, title, NULL, NULL);
glfwMakeContextCurrent(window); glfwMakeContextCurrent(window);
gladLoadGLLoader((GLADloadproc)glfwGetProcAddress); gladLoadGLLoader((GLADloadproc)glfwGetProcAddress);
glEnable(GL_DEPTH_TEST);
glEnable(GL_CULL_FACE);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
} }
bool RenderBackend::is_window_created() { bool RenderBackend::is_window_created() {

128
cpp/TextLabel.cpp Normal file
View File

@ -0,0 +1,128 @@
// 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() : 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, 48);
// 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::render_text(String 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>(500), 0.0f, static_cast<float>(500));
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

View File

@ -0,0 +1,37 @@
#pragma once
#include <ft2build.h>
#include <glm/glm.hpp>
#include <map>
#include FT_FREETYPE_H
#include "Gedeng/Shader.h"
#include "Gedeng/String.h"
#include "Gedeng/Vector3.h"
namespace Gedeng {
class TextLabel {
public:
TextLabel();
void render_text(String text, float x, float y, float scale, Vector3 color);
bool is_valid();
private:
struct Character {
unsigned int texture_id; // ID handle of the glyph texture
glm::ivec2 size; // Size of glyph
glm::ivec2 bearing; // Offset from baseline to left/top of glyph
unsigned int advance; // Offset to advance to next glyph
};
std::map<char, Character> characters;
unsigned int vao, vbo;
bool valid;
Shader shader;
};
} // namespace Gedeng

View File

@ -2,6 +2,14 @@
namespace Gedeng { namespace Gedeng {
class Vector3 {}; class Vector3 {
public:
Vector3(float x, float y, float z) : x(x), y(y), z(z) {
}
float x;
float y;
float z;
};
} // namespace Gedeng } // namespace Gedeng

View File

@ -1,4 +1,6 @@
#include "Gedeng/Logger.h" #include "Gedeng/Logger.h"
#include "Gedeng/TextLabel.h"
#include "Gedeng/Vector3.h"
#define GEDENG_MAIN #define GEDENG_MAIN
#include <Gedeng.h> #include <Gedeng.h>
@ -68,6 +70,9 @@ class ParallaxApp : public Gedeng::Application {
// Quad which is rendered onto // Quad which is rendered onto
quad_mesh.rotate(delta * 25.0f, glm::normalize(glm::vec3(0.0, 0.0, 1.0))); quad_mesh.rotate(delta * 25.0f, glm::normalize(glm::vec3(0.0, 0.0, 1.0)));
quad_mesh.render(render_shader); quad_mesh.render(render_shader);
debug_text.render_text(Gedeng::String("This is sample text"), 25.0f, 25.0f, 1.0f,
Gedeng::Vector3(1.0, 1.0, 0.0));
} }
private: private:
@ -86,6 +91,8 @@ class ParallaxApp : public Gedeng::Application {
Gedeng::Texture normal; Gedeng::Texture normal;
Gedeng::QuadMesh quad_mesh; Gedeng::QuadMesh quad_mesh;
Gedeng::TextLabel debug_text;
}; };
Gedeng::Application *Gedeng::create_application() { Gedeng::Application *Gedeng::create_application() {