【问题标题】:How to fix freetype incorrectly loading characters如何修复freetype错误加载字符
【发布时间】:2019-11-25 06:45:13
【问题描述】:

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 != '\0'; 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)

【问题讨论】:

  • 你确定缓冲区(face-&gt;glyph-&gt;bitmap.buffer)的格式是GL_RGBA而不是GL_RED
  • 我一开始是 GL_RED,但是什么都显示不了,所以我把它改成 GL_RGBA,得到了你可以看到的结果。

标签: c opengl-es textures raspberry-pi3 freetype2


【解决方案1】:

FT_Load_Char 返回的缓冲区为字形的每个像素包含一个字节。
如果您要使用现代 OpenGL,您可以使用格式 GL_RED 作为位图格式和内部纹理图像格式。其余的将执行Shader program
由于您使用Legacy OpenGL,因此您必须使用将字节值转换为 RGB 值的格式。为此使用GL_LUMINANCEGL_LUMINANCE" 转换为 RGBA 元素,方法是将红色、绿色和蓝色的亮度值复制 3 次,并为 alpha 附加 1"

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
);

注意,二维纹理必须启用,见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(); 之前调用。

【讨论】:

  • 我认为 OP 在调用 glTexImage2D 之前还必须使用 glPixelStorei(GL_UNPACK_ALIGNMENT, 1); 来处理 face-&gt;glyph-&gt;bitmap.width 不被 4 整除的情况。(或使用 FT_Bitmap_Convert
  • 这有点对,我唯一需要改变的是 GL_RGBA 到 GL_ALPHA,
猜你喜欢
  • 1970-01-01
  • 2018-09-09
  • 2011-02-20
  • 2023-03-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多