1

我正在使用freetype,为了呈现文本,我唯一要做的就是将ft_bitmap转换为可以用opengl呈现的东西有人可以解释如何做到这一点吗?我正在使用glfw。以我尝试这样做的方式,它只会给出一个空白屏幕这是我正在使用的代码:

    #include <exception>
    #include <iostream>
    #include <string>
    #include <glew.h>
    #include <GL/glfw.h>
    #include <iterator>
    #include "../include/TextRenderer.h"
    #include <ft2build.h>
    #include FT_FREETYPE_H
    #include <stdexcept>
    #include <freetype/ftglyph.h>


    using std::runtime_error;
    using std::cout;
    TextRenderer::TextRenderer(int x, int y, FT_Face Face, std::string s)
    {


        FT_Set_Char_Size(
            Face,    /* handle to face object           */
            0,       /* char_width in 1/64th of points  */
            16*64,   /* char_height in 1/64th of points */
            0,     /* horizontal device resolution    */
            0 );   /* vertical device resolution      */
        slot= Face->glyph;

        text = s;
        setsx(x);
        setsy(y);
        penX = x;
        penY = y;
        face = Face;
        //shaders
        GLuint v = glCreateShader(GL_VERTEX_SHADER) ;
        const char* vs = "void main(){  gl_Position = ftransform();}";
        glShaderSource(v,1,&vs,NULL);
        glCompileShader(v);
        GLuint f = glCreateShader(GL_FRAGMENT_SHADER) ;
        const char* fs = "uniform sampler2D texture1; void main() {    gl_FragColor = texture2D(texture1, gl_TexCoord[0].st); //And that is all we need}";
        glShaderSource(f,1,&fs,NULL);
        glCompileShader(f);
        Program= glCreateProgram();
        glAttachShader(Program,v);
        glAttachShader(Program,f);
        glLinkProgram(Program);


    }
    void TextRenderer::render()
    {
        glUseProgram(Program);
        FT_UInt  glyph_index;
        for ( int n = 0; n < text.size(); n++ )
        {
            /* retrieve glyph index from character code */

            glyph_index = FT_Get_Char_Index( face, text[n] );

                /* load glyph image into the slot (erase previous one) */
                error = FT_Load_Glyph( face, glyph_index, FT_LOAD_RENDER );

                draw(&face->glyph->bitmap,penX + slot->bitmap_left,penY - slot->bitmap_top );

                penX += *(&face->glyph->bitmap.width)+3;
                penY += slot->advance.y >> 6; /* not useful for now */
            }
        }
  void TextRenderer::draw(FT_Bitmap * bitmap,float x,float y)
{



GLuint texture [0] ;

    glGenTextures(1,texture);
    glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL);
glTexImage2D (GL_TEXTURE_2D, 0, GL_RED , bitmap->width, bitmap->rows, 0, GL_RED , GL_UNSIGNED_BYTE, bitmap);


//    int loc = glGetUniformLocation(Program, "texture1");
//    glUniform1i(loc, 0);
glBindTexture(GL_TEXTURE_2D, texture[0]);
glEnable(GL_TEXTURE_2D);
        int height=bitmap->rows/10;
        int width=bitmap->width/10;
        glBegin(GL_QUADS);
        glTexCoord2f (0.0, 0.0);
        glVertex2f(x,y);
        glTexCoord2f (1.0, 0.0);
        glVertex2f(x+width,y);
        glTexCoord2f (1.0, 1.0);
       glVertex2f(x+width,y+height);
       glTexCoord2f (0.0, 1.0);
        glVertex2f(x,y+height);
       glEnd();
glDisable(GL_TEXTURE_2D);

}

我用来初始化文本渲染器的东西:

FT_Library  library;
FT_Face     arial;
 FT_Error error = FT_Init_FreeType( &library );
    if ( error )
    {
        throw std::runtime_error("Freetype failed");
    }

    error = FT_New_Face( library,
                         "C:/Windows/Fonts/Arial.ttf",
                         0,
                         &arial );
    if ( error == FT_Err_Unknown_File_Format )
    {
        throw std::runtime_error("font format not available");
    }
    else if ( error )
    {
        throw std::runtime_error("Freetype font failed");
    }
TextRenderer t(5,10,arial,"Hello");
    t.render();
4

1 回答 1

3

您的程序中有很多问题是由于不了解您对 OpenGL 或 Freetype 所做的每个调用所做的。您应该真正阅读这些库的文档,而不是将教程相互堆叠。

让我们一一做

片段着色器

const char* fs = "uniform sampler2D texture1;
                  void main() {
                      gl_FragColor = texture2D(texture1, gl_TexCoord[0].st);
                  //And that is all we need}";`

这个着色器不编译(你应该真正检查它是否编译glGetShaderiv以及它是否与 链接glGetProgramiv)。如果你正确缩进它,那么你会看到你注释掉了最后},因为它在同一行中并且在//. 因此,您应该删除评论或使用 a\n结束评论。

此外,对于较新版本的 OpenGL,使用gl_TexCoord已被弃用,但如果您使用兼容性配置文件,它就可以工作。

顶点着色器

就像片段着色器一样,使用了不推荐使用的功能,即ftransform().

但更大的问题是您gl_TexCoord[0]在片段着色器中使用而没有从顶点着色器传递它。所以,你需要gl_TexCoord[0]=gl_MultiTexCoord0;在你的顶点着色器中添加这条线。(正如您可能已经猜到的那样,它也已被弃用)

纹理传递

您正在传递一个指向但类型为bitmap的指针,您需要改为传递。glTexImage2DbitmapFT_Bitmap *bitmap->buffer

您不应该为每帧的每个字母生成一个新纹理(尤其是如果您不删除它)。你应该glGentextures只调用一次(你可以把它放在你的TextRenderer构造函数中,因为你把所有其他初始化的东西都放在那里了)。

然后是GLuint texture [0];which 应该给你一个编译器错误。如果你真的需要一个包含一个元素的数组,那么语法是GLuint texture [1];

所以你最后的电话看起来像这样:

glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, bitmap->width, bitmap->rows, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, bitmap->buffer);

各种各样的

int height=bitmap->rows/10;
int width=bitmap->width/10;

这是一个整数除法,如果你的值bitmap->width小于10你得到0的结果,这将使你试图绘制的四边形不可见(高度或宽度为 0)。如果您无法将对象显示在视图中,您应该将其转换/缩放到视图中。这也已被弃用,但如果您继续使用其他东西,这将使您的窗口具有从 [-100,-100] 到 [100,100](左下角到右上角)的坐标系。

glLoadIdentity();
glScalef(0.01f, 0.01f, 1.0f);

您还缺少从 FreeType 到 OpenGL 的坐标转换,Freetype 使用的坐标系从左上角的 [0,0] 开始,x是向右y的偏移量,而是到底部的偏移量。因此,如果您只是在 OpenGL 中使用这些坐标,那么一切都会颠倒过来。

如果你做了所有这些,你的结果应该看起来像这样(灰色背景突出多边形开始和结束的位置):

glfw 窗口

至于您的一般方法,重新利用一个纹理并逐个字母地重新使用和覆盖相同的纹理似乎是一种低效的方法。最好只分配一个更大的纹理,然后用glTexSubImage2D它来写入字形。如果 freetype 重新渲染字母是一个瓶颈,您也可以在开始时将所需的所有符号写入一个纹理(例如整个 ASCII 范围),然后将该纹理用作纹理图集。

我的一般建议也是,如果您不是真的想学习 OpenGL,而只是想使用一些跨平台渲染而不用担心低级的东西,我建议您改用渲染框架。

于 2013-08-13T23:44:57.270 回答