'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 - and rotating the texture -
(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 |
---|