Add draft for text rendering
This commit is contained in:
parent
307d000253
commit
10138d5fd8
@ -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)
|
||||||
|
@ -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
128
cpp/TextLabel.cpp
Normal 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
|
37
include/Gedeng/TextLabel.h
Normal file
37
include/Gedeng/TextLabel.h
Normal 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
|
@ -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
|
@ -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() {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user