Aseed Kid
Aseed Kid

Reputation: 59

Characters centering weirdly in Freetype, OpenGL

I am trying to render some text inside a button (which is just a vec2 of button size and vec2 of button position), and I am trying to center the text inside the button. and it works for characters with the same height, such as 'a', 'c', 'x', 'z', and all the capital letters. But as soon as I add in a letter with a different height, the text centering gets all messed up.

Image to show that the text rendering gets messed up Image to show that the text rendering gets messed up

And this is the code I use to render text:

for (auto& item : buttons)
{
    buttonShader->use();
    buttonShader->setTexture2D("texture1", defaultTexture, 0);

    // Calculate the transform matrix for the button (NOT the text), i think it's relevant
    glm::mat4 transform = glm::mat4(1.0f);
    transform = glm::translate(transform, glm::vec3(item.position.x, item.position.y, 0.0f));
    transform = glm::scale(transform, glm::vec3(item.buttonSize.x, item.buttonSize.y, 1.0f));

    // This is where I set the uniforms inside the shader, irrelevant code

    // This is where I render the button with glDrawElements, irrelevant

    shader->use();
    glBindVertexArray(VAO);

    const std::string& text = item.text;
    const std::string& fontPath = item.font;

    float buttonWidth = item.buttonSize.x;
    float buttonHeight = item.buttonSize.y;
    float x = item.position.x - buttonWidth / 2.0f;
    float y = item.position.y - buttonHeight / 2.0f;

    glm::vec2 scale = item.textSize; 
    glm::vec3 color = glm::vec3(item.textColor.x, item.textColor.y, item.textColor.z);

    shader->setVec3("textColor", color);

    // Calculate the total width and height of the text
    float totalWidth = 0.0f;
    float maxHeight = 0.0f;
    for (auto c = text.begin(); c != text.end(); ++c) {
        Character ch = Fonts[fontPath][*c];
        totalWidth += (ch.Advance >> 6) * scale.x; // Advance is in 1/64 pixels
        maxHeight = std::max(maxHeight, static_cast<float>(ch.Size.y));
    }

    float startX = x + (buttonWidth - totalWidth) / 2.0f;
    float startY = y + (buttonHeight - maxHeight * scale.y) / 2.0f;

    for (auto c = text.begin(); c != text.end(); ++c) {
        Character ch = Fonts[fontPath][*c];

        float xpos = startX + ch.Bearing.x * scale.x; // Apply x scaling
        float ypos = startY + (ch.Size.y - ch.Bearing.y) * scale.y; 

        float w = ch.Size.x * scale.x; 
        float h = ch.Size.y * scale.y; 
        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 }
        };
        glBindTexture(GL_TEXTURE_2D, ch.TextureID);
        glBindBuffer(GL_ARRAY_BUFFER, VBO);
        glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(vertices), vertices);
        glBindBuffer(GL_ARRAY_BUFFER, 0);

        glDrawArrays(GL_TRIANGLES, 0, 6);

        startX += (ch.Advance >> 6) * scale.x;
    }
}

Upvotes: -2

Views: 89

Answers (1)

Sir Nate
Sir Nate

Reputation: 399

I see two issues:

  1. You should calculate a separate maxHeight and minHeight from the baseline separately (or use the line spacing/font metric height that is already provided). p and d will have similar Size values, but are positioned differently on the baseline, so you will underestimate the size you need for the button the way you are calculating it.
  2. (The main one causing your wrong positioning): You have flipped the signs in computing the positions. If +Y is up, then you need to start at the bottom BASELINE - (SizeY - BearingY) and go up to BASELINE + BearingY. Or the other way for +Y is down. Refer to the diagram from the freetype docs: freetype glyph bearing documentation

Upvotes: 1

Related Questions