Search code examples
ubuntuopenglbitmapglfwfreetype2

OpenGL FreeType2 bitmap not rendering


Trying to render a character using FreeType2 and this online tutorial, but having some issues and the results are pretty irregular. I've looked at the other questions on this website here and here and made those corrections but I'm still pretty stumped. I've made it through to the end but the bitmap isn't displaying properly:

Font bitmap

Not only that, but the display depends on the character that I'm trying to render. Some show up blank while others show up as a rectangle. Code is below, any advice would be greatly appreciated.

Main program:

#include <iostream>
#include <fstream>
#include <vector>

#include <GL/glew.h>
#include <GLFW/glfw3.h>

#define GLM_FORCE_RADIANS
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtx/transform.hpp>

#include <ft2build.h>
#include FT_FREETYPE_H

#include "OGLT.hpp"

OGLT Toolkit;
GLuint vao, vbo[2], shader, uniform_color, tex, uniform_tex;

static void key_callback(GLFWwindow * window, int key, int scancode, int action, int mods){
  if (key == GLFW_KEY_ESCAPE && action == GLFW_PRESS)
    glfwSetWindowShouldClose(window, GL_TRUE);
}

void MyInitialize(){
  // Initialize FreeType
  FT_Library library;
  FT_Face face;
  int error = FT_Init_FreeType(&library);
  if (error){
    std::cout << "An error occurred during library initialization!\n";
  }
  //error = FT_New_Face(library, "open-sans/OpenSans-Regular.ttf", 0, &face);
  error = FT_New_Face(library, "/usr/share/fonts/truetype/droid/DroidSans.ttf", 0, &face);
  if(error == FT_Err_Unknown_File_Format){
    std::cout << "The font file could be opened and read, but it appears " << 
  "that its font format is unsupported.\n";
  }
  else if(error){
    std::cout << "Another error code means that the font file could not be " <<
  "opened or read, or that it is broken.\n";
  }
  else std::cout << "Font file sucessfully loaded!\n";
  FT_Set_Pixel_Sizes(face, 0, 100);

  // Initialize GLEW and load shaders
  Toolkit.StartGLEW();

  // OpenGL state initialization
  glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
  glPixelStorei(GL_UNPACK_ALIGNMENT,1);
  glEnable(GL_DEPTH_TEST);
  glDepthFunc(GL_LESS);
  glEnable(GL_BLEND);
  glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

  // Vertex buffer initialization
  FT_Load_Char(face, 'W', FT_LOAD_RENDER);
  FT_GlyphSlot g = face->glyph;

  float x = 0.0f, y = 0.0f;
  float sx = 2.0/1000.0;
  float sy = 2.0/800.0;

  float x2 = x + g->bitmap_left * sx;
  float y2 = -y - g->bitmap_top * sy;
  float w = g->bitmap.width * sx;
  float h = g->bitmap.rows * sy;

  static float letter[] = {
    x2, -y2, 0.0f,
    x2+w, -y2, 0.0f,
    x2, -y2-h, 0.0f,
    x2+w, -y2-h, 0.0f,
  };
  static float letter_uv[] = {
    0.0f, 0.0f,
    1.0f, 0.0f,
    0.0f, 1.0f,
    1.0f, 1.0f
  };

  glGenVertexArrays(1, &vao);
  glBindVertexArray(vao);

  glGenBuffers(2, vbo);
  glBindBuffer(GL_ARRAY_BUFFER, vbo[0]);
  glBufferData(GL_ARRAY_BUFFER, sizeof(letter), letter, GL_STATIC_DRAW);

  GLuint VertexAttributeID = 0;
  glVertexAttribPointer(VertexAttributeID, 3, GL_FLOAT, GL_FALSE, 0, 0);
  glEnableVertexAttribArray(VertexAttributeID);

  glBindBuffer(GL_ARRAY_BUFFER, vbo[1]);
  glBufferData(GL_ARRAY_BUFFER, sizeof(letter_uv), letter, GL_STATIC_DRAW);

  GLuint UvAttributeID = 1;
  glVertexAttribPointer(UvAttributeID, 2, GL_FLOAT, GL_FALSE, 0, 0);
  glEnableVertexAttribArray(UvAttributeID);

  glBindVertexArray(0);
  glBindBuffer(GL_ARRAY_BUFFER, vbo[0]);

  glActiveTexture(GL_TEXTURE0);
  glGenTextures(1, &tex);
  glBindTexture(GL_TEXTURE_2D, tex);

  glTexImage2D(GL_TEXTURE_2D, 0, GL_R8, g->bitmap.width, g->bitmap.rows, 0,
      GL_RED, GL_UNSIGNED_BYTE, g->bitmap.buffer);
  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);

  shader = Toolkit.LoadShaders("test_vertex.glsl", "test_fragment.glsl");
  uniform_color = glGetUniformLocation(shader, "color");
  uniform_tex = glGetUniformLocation(shader, "texture_sampler");
}

void MyDisplay(GLFWwindow * window){
  int width, height;
  glfwGetFramebufferSize(window, &width, &height);
  glViewport(0, 0, width, height);
  glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

  glUseProgram(shader);

  glm::vec4 ColorVec = glm::vec4(0.0f, 1.0f, 0.0f, 1.0f);
  glUniform4fv(uniform_color, 1, &ColorVec[0]);
  glUniform1i(uniform_tex, 0);

  glBindVertexArray(vao);
  glActiveTexture(GL_TEXTURE0);
  glBindTexture(GL_TEXTURE_2D, tex);
  glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);

  glBindVertexArray(0);
  glBindBuffer(GL_ARRAY_BUFFER, 0);
  glBindTexture(GL_TEXTURE_2D, 0);
  glUseProgram(0);
}

int main(){
  // Initialize window
  GLFWwindow * window;

  // Initialize the library
  if(!glfwInit()) return -1;

  glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
  glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
  glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);

  // Create a windowed mode window and its OpenGL context
  window = glfwCreateWindow(1000, 800, "Font Test", NULL, NULL);
  if(!window){
    glfwTerminate();
    return -1;
  }

  // Make the window's context current
  glfwMakeContextCurrent(window);
  glfwSwapInterval(1);
  glfwSetKeyCallback(window, key_callback);

  MyInitialize();

  // Loop until the user closes the window
  while(!glfwWindowShouldClose(window)){
    // Render here
    MyDisplay(window);
    // Swap front and back buffers
    glfwSwapBuffers(window);
    // Poll for and process events
    glfwPollEvents();
  }
  glfwDestroyWindow(window);
  glfwTerminate();

  return 0;
}

Vertex shader:

#version 330 core

layout (location = 0) in vec3 vertex;
layout (location = 1) in vec2 vertex_uv;
out vec2 uv;

void main(){
  gl_Position = vec4(vertex.xyz, 1);
  uv = vertex_uv;
}

Fragment shader:

#version 330 core

in vec2 uv;
uniform vec4 color;
uniform sampler2D texture_sampler;
out vec4 color_out;

void main(){
  color_out = vec4(1.0, 1.0, 1.0, texture(texture_sampler, uv).r) * color;
}

Solution

  • If you will try to display different chars you will see that you display only a portion of it wich should lead you to the reason of the error. It's in the code of uploading a uv buffer, a simple copy_paste mistake:

    glBufferData(GL_ARRAY_BUFFER, sizeof(letter_uv), letter, GL_STATIC_DRAW);
    

    the 3rd argument sould be letter_uv