PDA

View Full Version : Rendering Text with FreeType doesn't work



Michael25
04-23-2016, 02:31 AM
Hi!

I recently tried to render text using FreeType, I followed a tutorial findable at the website of learnopengl and even though the code seems to be OK it's not working, I don't have any errors, just nothing displayed.

I posted a message there but I'm a little in a hurry, so I came here. I hope you'll find the error in this code!

Main Loop:


void Scene::mainLoop() {
// Matrices
mat4 projection;
projection = perspective(70.0, (double) m_winWidth / m_winHeight, 0.1, 100.0);
mat4 modelview = mat4(1.0);

// Camera
Camera camera(vec3(3, 3, 5), vec3(0, 0, 0), vec3(0, 1, 0), 0.5, 0.5);

// Init FreeType
m_output.initShader();
m_output.initFreeType();

// Enable Blend
glEnable(GL_CULL_FACE);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

// MAIN LOOP
while (!m_input.getEndProgram()) {
// Setting loop started time
m_loopStart = SDL_GetTicks();

// Events handling
m_input.updateEvents();

// Move mouse function
camera.move(m_input);

// Escape - Exit program
if (m_input.getKeyCode(SDL_SCANCODE_ESCAPE))
break;

// Screen clearing
glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);

// Camera handling
camera.lookAt(modelview);

m_output.RenderText("This is sample text", 50.0f, 50.0f, 1.0f, glm::vec3(0.5, 0.8f, 0.2f));
m_output.RenderText("This is sample text2", 50.0f, -50.0f, 1.0f, glm::vec3(0.5, 0.8f, 0.2f));
m_output.RenderText("This is sample text3", 500.0f, 475.0f, 0.5f, glm::vec3(0.5, 0.8f, 0.2f));
m_output.RenderText("This is sample text4", 0.0f, 0.0f, 1.0f, glm::vec3(0.5, 0.8f, 0.2f));

// Window updating
SDL_GL_SwapWindow(m_window);

// Check FPS
calculateFPS(m_fps, m_frameCount, m_currentTime, m_previousTime);

// Check execution time
checkElapsedTime();
}
}


Output class (header):


#ifndef DEF_OUTPUT
#define DEF_OUTPUT

// Windows includes
#ifdef WIN32
#include <GL/glew.h>
#include <SDL2/SDL_image.h>
#endif

// GLM Includes
#include <glm/glm.hpp>
#include <glm/gtx/transform.hpp>
#include <glm/gtc/type_ptr.hpp>

// Other includes
#include <iostream>
#include <map>
#include <string>
#include <vector>

// File include
#include "shader.h"

#include <ft2build.h>
#include FT_FREETYPE_H

#ifndef BUFFER_OFFSET
#define BUFFER_OFFSET(offset) ((char*)NULL + (offset))
#endif

class Output {
public:

// Constructors and destructors
Output();
~Output();

// Method
void initFreeType();
void initShader();
void RenderText(std::string text, GLfloat x, GLfloat y, GLfloat scale, glm::vec3 color);

private:

struct Character {
GLuint TextureID; // ID handle of the glyph texture
glm::ivec2 Size; // Size of glyph
glm::ivec2 Bearing; // Offset from baseline to left/top of glyph
GLuint Advance; // Offset to advance to next glyph
};

// Windows parameters
int m_winWidth;
int m_winHeight;

Shader m_shader;
glm::mat4 m_orthoMat;

GLuint m_vbo;
GLuint m_vao;

std::map<GLchar, Character> Characters;
};
#endif


initFreeType function:


void Output::initFreeType() {
// Init freetype
FT_Library ft;
if (FT_Init_FreeType(&ft)) {
std::cout << "Could not init freetype library!" << std::endl;
}

// Init font
FT_Face face;
if (FT_New_Face(ft, "arial.ttf", 0, &face)) {
std::cout << "Could not open font!" << std::endl;
}

// Set size
FT_Set_Pixel_Sizes(face, 0, 48);

// Disable byte-alignment restriction
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);

for (GLubyte c = 0; c < 128; c++) {
// Load character glyph
if (FT_Load_Char(face, c, FT_LOAD_RENDER)) {
std::cout << "Failed to load Glyph" << std::endl;
continue;
}

// Generate texture
GLuint texture = 0;
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),
face->glyph->advance.x
};
Characters.insert(std::pair<GLchar, Character>(c, character));
}

// Release
FT_Done_Face(face);
FT_Done_FreeType(ft);

// Initialize VAO and VBO

// Deleting a potential former VBO
if(glIsBuffer(m_vbo) == GL_TRUE)
glDeleteBuffers(1, &m_vbo);

// Generate VBO ID
glGenBuffers(1, &m_vbo);

// Binding VBO
glBindBuffer(GL_ARRAY_BUFFER, m_vbo);

// Allocate video memory
glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * 24, 0, GL_DYNAMIC_DRAW); // Changed NULL to 0

// Unbinding VBO
glBindBuffer(GL_ARRAY_BUFFER, 0);

// Deleting a potential former VAO
if(glIsVertexArray(m_vao) == GL_TRUE)
glDeleteVertexArrays(1, &m_vao);

// Generate VAO ID
glGenVertexArrays(1, &m_vao);

// Binding VAO
glBindVertexArray(m_vao);

// Binding VBO
glBindBuffer(GL_ARRAY_BUFFER, m_vbo);

// Access vertices in the VRAM
glVertexAttribPointer(3, 4, GL_FLOAT, GL_FALSE, 4 * sizeof(GLfloat), 0);
glEnableVertexAttribArray(3);

// Unbinding VBO
glBindBuffer(GL_ARRAY_BUFFER, 0);

// Unbinding VAO
glBindVertexArray(0);
}


RenderText function:


void Output::RenderText(std::string text, GLfloat x, GLfloat y, GLfloat scale, glm::vec3 color) {
if (!m_isShaderLoaded)
return;

// Activate corresponding render state
glUseProgram(m_shader.getProgramID());

// Send colour
glUniform3f(glGetUniformLocation(m_shader.getProgr amID(), "textColor"), color.x, color.y, color.z);
glActiveTexture(GL_TEXTURE0);

// Send ortho matrix
m_shader.sendMat4("projection", m_orthoMat);

glBindVertexArray(m_vao);

// Iterate through all characters
std::string::const_iterator c;
for (c = text.begin(); c != text.end(); c++) {
Character ch = Characters[*c];

GLfloat xpos = x + ch.Bearing.x * scale;
GLfloat ypos = y - (ch.Size.y - ch.Bearing.y) * scale;

GLfloat w = ch.Size.x * scale;
GLfloat h = ch.Size.y * scale;

// Update VBO for each character
GLfloat vertices[6][4] = {
{xpos, ypos + h, 0.0, 0.0},
{xpos, ypos, 0.0, 1.0},
{xpos + w, ypos, 1.0, 1.0},

{xpos, ypos + h, 0.0, 0.0},
{xpos + w, ypos, 1.0, 1.0},
{xpos + w, ypos + h, 1.0, 0.0}
};

// Render glyph texture over quad
glBindTexture(GL_TEXTURE_2D, ch.TextureID);

// Update content of VBO memory
glBindBuffer(GL_ARRAY_BUFFER, m_vbo);
glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(vertices), vertices);
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)
}

// Unbindings
glBindVertexArray(0);
glBindTexture(GL_TEXTURE_2D, 0);

// Exit shader program
glUseProgram(0);
}


Vertex Shader:


// GLSL Version
#version 330 core

layout(location = 0) in vec4 vertex; // <vec2 pos, vec2 tex>

out vec2 TexCoords;

uniform mat4 projection;

void main() {
gl_Position = projection * vec4(vertex.xy, 0.0, 1.0);
TexCoords = vertex.zw;
}


Fragment Shader:


// GLSL Version
#version 330 core

in vec2 TexCoords;
out vec4 color;

uniform sampler2D text;
uniform vec3 textColor;

void main() {
vec4 sampled = vec4(1.0, 1.0, 1.0, texture(text, TexCoords).r);
color = vec4(textColor, 1.0) * sampled;
}


Projection matrix initialization:


m_orthoMat = glm::ortho(0.0f, m_winWidth, 0.0f, m_winHeight);


Here is the complete project files in case you'd want it:
https://drive.google.com/open?id=0B1HyjpNmBqd7LU9hWGIxMlV2MlU

Michael25
05-17-2016, 04:47 AM
Hi,

It's me again. Since no one answered to my post I'm closing it. The shared files will no longer be available.

Have a nice day.

Michael