如何修复 freetype 错误加载字符
How to fix freetype incorrectly loading characters
FreeType 库打开并加载字体时不会出现错误,但当我尝试使用字符纹理时,它们会重复且上下颠倒。
我正在使用 OpenGL 创建一个基于图形的程序,以处理我使用 FreeType 的字体和文本。当我加载纹理并设置它时,会提供正确的大小和字形属性(宽度、高级等...),但是当我使用位图创建纹理并使用该纹理时,它是不正确的(如前所述)。
这里是初始化代码:
FT_Init_FreeType(&ft);
FT_New_Face(ft, "Roboto.ttf", 0, &face);
FT_Set_Pixel_Sizes(face, 0, 100);
getChars();
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
FT_Done_Face(face);
FT_Done_FreeType(ft);
这是获取角色纹理的代码:
void getChars(){
int index = 0;
for (GLubyte c = 0; c < 128; c++){
if (FT_Load_Char(face, c, FT_LOAD_RENDER)){
printf("couldn't load character\n");
continue;
}
GLuint texture;
glGenTextures(1,&texture);
glBindTexture(GL_TEXTURE_2D, texture);
glTexImage2D(GL_TEXTURE_2D,0,GL_RGBA,face->glyph->bitmap.width,face->glyph->bitmap.rows,0,GL_RGBA,GL_UNSIGNED_BYTE,face->glyph->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);
Character character = {texture, {face->glyph->bitmap.width, face->glyph->bitmap.rows}, {face->glyph->bitmap_left, face->glyph->bitmap_top}, face->glyph->advance.x};
chars[index++] = character;
}
printf("Got characters\n");
}
我已经注释掉了对纹理显示方式没有任何影响的 glTexParameteri
以下是用于存储纹理的结构:
typedef struct vec2 {
float x;
float y;
} vec2;
typedef struct Character {
GLuint Texture;
vec2 Size;
vec2 Bearing;
GLuint Advance;
} Character;
Character chars[128];
最后是显示传递给它的字符串的代码:
void drawText(char* inString, float x, float y, float scale, colour col) {
for (char* string = inString; *string != '[=13=]'; string++){
Character ch = chars[(int) *string];
glBindTexture( GL_TEXTURE_2D, ch.Texture);
printf("character\n");
float xpos = x + ch.Bearing.x * scale * 2 /glutGet(GLUT_WINDOW_WIDTH);
float ypos = y - (ch.Size.y - ch.Bearing.y) * scale * 2 /glutGet(GLUT_WINDOW_HEIGHT);
float w = ch.Size.x * scale * 2 /glutGet(GLUT_WINDOW_WIDTH);
float h = ch.Size.y * scale * 2 /glutGet(GLUT_WINDOW_HEIGHT);
//draws the textured QUAD
glBegin(GL_QUADS);
//set the colour of the quad the texutre blends with to white with the appropriate opacity
glColor4f(col.R, col.G, col.B, col.A);
glTexCoord2f(0.0,0.0);
glVertex2f(xpos, ypos);
glTexCoord2f(0.0,1.0);
glVertex2f(xpos, ypos+h);
glTexCoord2f(1.0,1.0);
glVertex2f(xpos+w, ypos+h);
glTexCoord2f(1.0,0.0);
glVertex2f(xpos+w, ypos);
glEnd();
x += (ch.Advance >> 6) * scale * 2 /glutGet(GLUT_WINDOW_WIDTH);
printf("w %1.0f\n",w);
printf("h %1.0f\n",h);
printf("x %1.0f\n",xpos);
printf("y %1.0f\n",ypos);
}
}
我希望加载普通文本,但如前所述,每个字符看起来都像自己的纹理贴图
this is the way the text looks (ignore the image behind it)
FT_Load_Char
返回的缓冲区包含字形的每个像素一个字节。
如果您要使用现代 OpenGL,则可以对位图格式和内部纹理图像格式使用 GL_RED
格式。剩下的会做 Shader program.
由于您使用 Legacy OpenGL you've to use a format that converts the byte value to an RGB value. Use GL_LUMINANCE
for that. GL_LUMINANCE
转换 "into an RGBA element by replicating the luminance value three times for red, green, and blue and attaching 1 for alpha".
glTexImage2D(
GL_TEXTURE_2D,
0,
GL_LUMINANCE,
face->glyph->bitmap.width,
face->glyph->bitmap.rows,
0,
GL_LUMINANCE,
GL_UNSIGNED_BYTE,
face->glyph->bitmap.buffer
);
请注意必须启用 two-dimensional 纹理,请参阅 glEnable
:
glEnable(GL_TEXTURE_2D)
如果你想用透明背景绘制文本,那么你可以使用GL_ALPHA
:
glTexImage2D(
GL_TEXTURE_2D,
0,
GL_ALPHA,
face->glyph->bitmap.width,
face->glyph->bitmap.rows,
0,
GL_ALPHA,
GL_UNSIGNED_BYTE,
face->glyph->bitmap.buffer
);
绘制文字时,必须启用Blending
:
void drawText(char* inString, float x, float y, float scale, colour col) {
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glEnable(GL_TEXTURE_2D);
// [...]
glDisable(GL_TEXTURE_2D);
glDisable(GL_BLEND);
}
另外 glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
应该在 getChars();
之前调用。
FreeType 库打开并加载字体时不会出现错误,但当我尝试使用字符纹理时,它们会重复且上下颠倒。
我正在使用 OpenGL 创建一个基于图形的程序,以处理我使用 FreeType 的字体和文本。当我加载纹理并设置它时,会提供正确的大小和字形属性(宽度、高级等...),但是当我使用位图创建纹理并使用该纹理时,它是不正确的(如前所述)。
这里是初始化代码:
FT_Init_FreeType(&ft);
FT_New_Face(ft, "Roboto.ttf", 0, &face);
FT_Set_Pixel_Sizes(face, 0, 100);
getChars();
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
FT_Done_Face(face);
FT_Done_FreeType(ft);
这是获取角色纹理的代码:
void getChars(){
int index = 0;
for (GLubyte c = 0; c < 128; c++){
if (FT_Load_Char(face, c, FT_LOAD_RENDER)){
printf("couldn't load character\n");
continue;
}
GLuint texture;
glGenTextures(1,&texture);
glBindTexture(GL_TEXTURE_2D, texture);
glTexImage2D(GL_TEXTURE_2D,0,GL_RGBA,face->glyph->bitmap.width,face->glyph->bitmap.rows,0,GL_RGBA,GL_UNSIGNED_BYTE,face->glyph->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);
Character character = {texture, {face->glyph->bitmap.width, face->glyph->bitmap.rows}, {face->glyph->bitmap_left, face->glyph->bitmap_top}, face->glyph->advance.x};
chars[index++] = character;
}
printf("Got characters\n");
}
我已经注释掉了对纹理显示方式没有任何影响的 glTexParameteri
以下是用于存储纹理的结构:
typedef struct vec2 {
float x;
float y;
} vec2;
typedef struct Character {
GLuint Texture;
vec2 Size;
vec2 Bearing;
GLuint Advance;
} Character;
Character chars[128];
最后是显示传递给它的字符串的代码:
void drawText(char* inString, float x, float y, float scale, colour col) {
for (char* string = inString; *string != '[=13=]'; string++){
Character ch = chars[(int) *string];
glBindTexture( GL_TEXTURE_2D, ch.Texture);
printf("character\n");
float xpos = x + ch.Bearing.x * scale * 2 /glutGet(GLUT_WINDOW_WIDTH);
float ypos = y - (ch.Size.y - ch.Bearing.y) * scale * 2 /glutGet(GLUT_WINDOW_HEIGHT);
float w = ch.Size.x * scale * 2 /glutGet(GLUT_WINDOW_WIDTH);
float h = ch.Size.y * scale * 2 /glutGet(GLUT_WINDOW_HEIGHT);
//draws the textured QUAD
glBegin(GL_QUADS);
//set the colour of the quad the texutre blends with to white with the appropriate opacity
glColor4f(col.R, col.G, col.B, col.A);
glTexCoord2f(0.0,0.0);
glVertex2f(xpos, ypos);
glTexCoord2f(0.0,1.0);
glVertex2f(xpos, ypos+h);
glTexCoord2f(1.0,1.0);
glVertex2f(xpos+w, ypos+h);
glTexCoord2f(1.0,0.0);
glVertex2f(xpos+w, ypos);
glEnd();
x += (ch.Advance >> 6) * scale * 2 /glutGet(GLUT_WINDOW_WIDTH);
printf("w %1.0f\n",w);
printf("h %1.0f\n",h);
printf("x %1.0f\n",xpos);
printf("y %1.0f\n",ypos);
}
}
我希望加载普通文本,但如前所述,每个字符看起来都像自己的纹理贴图
this is the way the text looks (ignore the image behind it)
FT_Load_Char
返回的缓冲区包含字形的每个像素一个字节。
如果您要使用现代 OpenGL,则可以对位图格式和内部纹理图像格式使用 GL_RED
格式。剩下的会做 Shader program.
由于您使用 Legacy OpenGL you've to use a format that converts the byte value to an RGB value. Use GL_LUMINANCE
for that. GL_LUMINANCE
转换 "into an RGBA element by replicating the luminance value three times for red, green, and blue and attaching 1 for alpha".
glTexImage2D(
GL_TEXTURE_2D,
0,
GL_LUMINANCE,
face->glyph->bitmap.width,
face->glyph->bitmap.rows,
0,
GL_LUMINANCE,
GL_UNSIGNED_BYTE,
face->glyph->bitmap.buffer
);
请注意必须启用 two-dimensional 纹理,请参阅 glEnable
:
glEnable(GL_TEXTURE_2D)
如果你想用透明背景绘制文本,那么你可以使用GL_ALPHA
:
glTexImage2D(
GL_TEXTURE_2D,
0,
GL_ALPHA,
face->glyph->bitmap.width,
face->glyph->bitmap.rows,
0,
GL_ALPHA,
GL_UNSIGNED_BYTE,
face->glyph->bitmap.buffer
);
绘制文字时,必须启用Blending
:
void drawText(char* inString, float x, float y, float scale, colour col) {
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glEnable(GL_TEXTURE_2D);
// [...]
glDisable(GL_TEXTURE_2D);
glDisable(GL_BLEND);
}
另外 glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
应该在 getChars();
之前调用。