Search code examples
c++openglglslglm-mathfreetype

How to bottom align the Font


With the help of @Rabbid76 and some web tutorials i have been able to render font in my scene.

The problem i am now facing is that font appears as top aligned instead of bottom aligned.

enter image description here

what i can do is to move the characters down in y position when the letter is not capitol.

1) Would this be the correct way to handle this issue or do we have any standard way of dealing with this.

The function to Load the font and render texture

 void MyFont::Load(std::string font, GLuint fontSize)
  {// First clear the previously loaded Characters
    this->Characters.clear();
    // Then initialize and load the FreeType library
    FT_Library ft;
    if (FT_Init_FreeType(&ft)) // All functions return a value different 
    than 0 whenever an error occurred
    std::cout << "ERROR::FREETYPE: Could not init FreeType Library" << 
   std::endl;
// Load font as face
FT_Face face;
if (FT_New_Face(ft, font.c_str(), 0, &face))
    std::cout << "ERROR::FREETYPE: Failed to load font" << std::endl;
// Set size to load glyphs as
FT_Set_Pixel_Sizes(face, 0, fontSize);
// Disable byte-alignment restriction
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
// Then for the first 128 ASCII characters, pre-load/compile their characters and store them
for (GLubyte c = 0; c < 128; c++) // lol see what I did there 
{
    // Load character glyph 
    if (FT_Load_Char(face, c, FT_LOAD_RENDER))
    {
        std::cout << "ERROR::FREETYTPE: Failed to load Glyph" << std::endl;
        continue;
    }
    // Generate texture
    GLuint 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),
        face->glyph->advance.x
    };
    Characters.insert(std::pair<GLchar, Character>(c, character));
}
glBindTexture(GL_TEXTURE_2D, 0);
// Destroy FreeType once we're finished
FT_Done_Face(face);
FT_Done_FreeType(ft);
}

The function to map the texture on rectangles.

 void MyFont::RenderText(std::string text, GLfloat x, GLfloat y, GLfloat 
  scale, glm::vec3 color)
  {
this->TextShader.Use();
// Activate corresponding render state
glm::mat4 model = glm::rotate(glm::mat4(1.0f), glm::radians(0.0f), 
 glm::vec3(0.0f, 1.0f, 0.0f));
     model = glm::translate(model, glm::vec3(-4.0, -1.0, 0.0));
glm::mat4 view = camera7.GetViewMatrix();
this->TextShader.SetMatrix4("model", model);
this->TextShader.SetMatrix4("view", view);

this->TextShader.SetVector3f("textColor", color);
this->TextShader.SetMatrix4("projection", 
 glm::perspective(glm::radians(45.0f), (float)800.0 / (float)600.0, 0.1f, 
  100.0f));
glActiveTexture(GL_TEXTURE0);
glBindVertexArray(this->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) * 0.1;   // Scaling the xpos value
    GLfloat ypos = (y + (this->Characters['H'].Bearing.y - ch.Bearing.y) * scale )* 0.1;  // Scaling the ypos value
    GLfloat w = ch.Size.x * scale;
    GLfloat h = ch.Size.y * scale;
    w /= 10.f;  // Scaling here
    h /= 10.f;  // scaling here

    // Update VBO for each character
    GLfloat vertices[6][5] = {

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

        { xpos,     ypos + h, 0.0,      0.0, 0.0 },
        { xpos + w, ypos + h, 0.0,      1.0, 0.0 },
        { xpos + w, ypos,     0.0,       1.0, 1.0 }
    };
    // Render glyph texture over quad
    glBindTexture(GL_TEXTURE_2D, ch.TextureID);
    // Update content of VBO memory
    glBindBuffer(GL_ARRAY_BUFFER, this->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
    x += (ch.Advance >> 6) * scale; // Bitshift by 6 to get value in pixels (1/64th times 2^6 = 64)


}
glBindVertexArray(0);
glBindTexture(GL_TEXTURE_2D, 0);

}

Solution

  • The easiest way to compensate that is to flip the y-component of the vertex coordinate and the v-component of the texture coordinate.

    Change pos + h to pos - h and swap 0.0 and 1.0:

    GLfloat vertices[6][5] = {
      //  x         y         z         u    v
        { xpos,     ypos - h, 0.0 ,     0.0, 1.0 },
        { xpos + w, ypos,     0.0 ,     1.0, 0.0 },
        { xpos,     ypos,     0.0 ,     0.0, 0.0 },
    
        { xpos,     ypos - h, 0.0,      0.0, 1.0 },
        { xpos + w, ypos - h, 0.0,      1.0, 1.0 },
        { xpos + w, ypos,     0.0,      1.0, 0.0 }
    };
    

    Note the base of the text changes from top to bottom in this case.