'Freetype: How to get the rotated text bounds

I am rendering a font atlas with rotated characters since my whole text box is rotated. Now I want to calculate the text box outline to render a colored background.

If I just calculate the minimum enclosing rectangle of the rendered vertices, this produces a misaligned box, since the characters are rotated in the texture atlas (cf. 1). I also rendered the texture cut-outs for better understanding of the problem (cf. 2):

Code for the character atlas creation:

#include <ft2build.h>
#include FT_FREETYPE_H
....
FT_Face face = ...
int height = ...
int angle = ...
FT_Set_Pixel_Sizes(face, 0, height);
FT_GlyphSlot g = face->glyph;

int roww = border;
int rowh = 0;
int w = 0;
int h = 0;

FT_Matrix     matrix;              /* transformation matrix */
const float angleF = angle / 180.f * PI;
matrix.xx = (FT_Fixed)(cos(angleF) * 0x10000L);
matrix.xy = (FT_Fixed)(-sin(angleF) * 0x10000L);
matrix.yx = (FT_Fixed)(sin(angleF) * 0x10000L);
matrix.yy = (FT_Fixed)(cos(angleF) * 0x10000L);
FT_Set_Transform(face, &matrix, 0);

memset(character, 0, sizeof character);

/* Find minimum size for a texture holding all visible ASCII characters */
for (int i = 32; i < Character::MAXIMUM; i++) {
    if (FT_Load_Char(face, i, FT_LOAD_RENDER)) {
        fprintf(stderr, "Loading character %c failed! Height is %d\n", i, height);
        continue;
    }
    if (roww + g->bitmap.width + 1 + border >= MAXWIDTH) {
        w = std::max(w, roww);
        h += rowh;
        roww = border;
        rowh = 0;
    }
    roww += g->bitmap.width + 1 + border;
    rowh = std::max(rowh, (int)g->bitmap.rows + border);
}

w = std::max(w, roww);
h += rowh + border;

glUseProgram(0);
glEnable(GL_TEXTURE_2D);

/* Create a texture that will be used to hold all ASCII glyphs */

glActiveTexture(GL_TEXTURE0);
if (!OpenGLResourceManager::emptyTexture(tex, w, h, 1)) {
    // Texture loading failed. Keep this atlas empty
    glDisable(GL_TEXTURE_2D);
    return;
}
tex.bindTexture();

/* We require 1 byte alignment when uploading texture data */
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);

{
    //Fill texture with black to prevent texture bleeding
    std::vector<GLubyte> emptyData(w * h, 0);
    glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, w, h, GL_LUMINANCE, GL_UNSIGNED_BYTE, &emptyData[0]);
}

/* Clamping to edges is important to prevent artifacts when scaling */
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);

/* Linear filtering usually looks best for text */
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

/* Paste all glyph bitmaps into the texture, remembering the offset */
int ox = border;
int oy = border;

rowh = 0;

for (int i = 32; i < Character::MAXIMUM; i++) {
    if (FT_Load_Char(face, i, FT_LOAD_RENDER)) {
        fprintf(stderr, "Loading character %c failed!\n", i);
        continue;
    }

    if (ox + g->bitmap.width + 1 + border >= MAXWIDTH) {
        oy += rowh;
        rowh = 0;
        ox = border;
    }
    glTexSubImage2D(GL_TEXTURE_2D, 0, ox, oy, g->bitmap.width, g->bitmap.rows, GL_RED, GL_UNSIGNED_BYTE, g->bitmap.buffer);
    character[i].ax = g->advance.x >> 6;
    character[i].ay = g->advance.y >> 6;

    character[i].bw = g->bitmap.width;
    character[i].bh = g->bitmap.rows;

    character[i].bl = g->bitmap_left;
    character[i].bt = g->bitmap_top;

    character[i].tx = ox / (float)w;
    character[i].ty = oy / (float)h;

    rowh = std::max(rowh, (int)g->bitmap.rows + border);
    ox += g->bitmap.width + 1 + border;
}

glBindTexture(GL_TEXTURE_2D, NULL);
glDisable(GL_TEXTURE_2D);
glPixelStorei(GL_UNPACK_ALIGNMENT, 4);  //Standard

How do I get the visual boundaries (and not the vertex boundaries) of the text?

UPDATE: Rotating the texture and not the vertices has to be done for pixel-perfect fonts, see the following close-ups:

rotating the vertices - Vertex rotationand rotating the texture - Texture rotation

(please ignore the difference in the drop shadow)



Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source