Рендеринг шрифтов с помощью Freetype и OpenGL

У меня проблема с фритайпом и OpenGL. Мне нужно просто нарисовать все загруженные символы на одной текстуре. Вот:

    FT_Init_FreeType(&lib);
    FT_New_Face(lib, "C:\\verdana.ttf", 0, &face);
    FT_Set_Pixel_Sizes(face, 0, size);

    auto ww = 256 * size;
    auto hh = size;

    std::vector<unsigned char> buffer(ww * hh, 0);

    int off = 0;

    for (int c = 0; c < 256; c++)
    {
        FT_UInt GlyphIndex;

        GlyphIndex = FT_Get_Char_Index(face, c);

        FT_Load_Char(face, GlyphIndex, FT_LOAD_RENDER);

        FT_Bitmap bmp = face->glyph->bitmap;

        int advance = (face->glyph->advance.x >> 6);
        int bW = bmp.width; 
        int bH = bmp.rows;

        for (int h = 0; h < bH; ++h) {
            for (int w = 0; w < bW; ++w) {

                buffer[h * bW + off + w] = bmp.buffer[w + bW * h];
            }
        }

        off += advance;

    }


    glGenTextures(1, &texture);
    glBindTexture(GL_TEXTURE_2D, texture);

    glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
    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);

    glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, ww, hh, 0, GL_ALPHA, GL_UNSIGNED_BYTE, &buffer[0]);

Я пробовал много способов сделать это. Но все, что я получаю, это абсолютно черная текстура... Что не так с моим кодом?


person user3808059    schedule 03.12.2014    source источник
comment
Вы проверяли коды ошибок, возвращаемые FT_Init_FreeType, FT_New_Face и т. д.? Кроме того, может потребоваться вызов FT_Set_Char_Size.   -  person BDL    schedule 03.12.2014
comment
Я не ловлю ошибок ни в одной части кода. Я установил размер символов с помощью FT_Set_Pixel_Sizes.   -  person user3808059    schedule 03.12.2014
comment
Но вы и не проверяете на ошибки. Каждая функция свободного типа возвращает значение, указывающее на успех/неуспех. Например: error = FT_Init_FreeType( &library ); if ( error ) { failed; }   -  person BDL    schedule 03.12.2014
comment
Поверьте мне, я сделал это до того, как написал здесь...   -  person user3808059    schedule 03.12.2014
comment
Еще одна вещь, которую я только что отметил: FT_Load_Char предполагает код символа в качестве второго параметра вместо индекса глифа. Может быть, вы имели в виду FT_Load_Glyph?   -  person BDL    schedule 03.12.2014
comment
ну это я поправил, но все работает так же.   -  person user3808059    schedule 03.12.2014
comment
Следующая попытка :) : off — это смещение в вашем линейном буфере, которое отмечает, где начинается следующий символ. тогда вы должны увеличивать его на каждой итерации на bW * bH вместо продвижения. Advance сообщает вам, на каком расстоянии в пикселях должна отображаться следующая буква на экране, это не имеет ничего общего с размером изображения.   -  person BDL    schedule 03.12.2014
comment
Извините, но опять нет. Мой последний результат выглядит так: i59.tinypic.com/1zfmz6g.jpg   -  person user3808059    schedule 03.12.2014


Ответы (2)


Я думаю, проблема в том, что некоторые значения между 0-255 не видны или не отображаются, и поэтому вы ничего не получаете.

вы должны проверить GlyphIndex:

GlyphIndex = FT_Get_Char_Index(face, c);
if (!GlyphIndex) continue;

тогда вы можете ожидать, что freetype нарисует остальные символы для вас.

person Omid    schedule 19.06.2017

Аллилуйя, я нашел решение!

Это должно выглядеть так:

for (int c = 0; c < 256; c++)
    {
        FT_UInt GlyphIndex;

        GlyphIndex = FT_Get_Char_Index(face, c);

        FT_Load_Char(face, GlyphIndex, FT_LOAD_RENDER);

        FT_Bitmap bmp = face->glyph->bitmap;

        int advance = (face->glyph->advance.x >> 6);
        int bW = bmp.width; 
        int bH = bmp.rows;

        for (int h = 0; h < bH; ++h) {
            for (int w = 0; w < bW; ++w) {

                buffer[h * ww + off + w] = bmp.buffer[w + bW * h];
            }
        }

        off += advance;

    }


    glGenTextures(1, &texture);
    glBindTexture(GL_TEXTURE_2D, texture);

    glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
    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);

    glTexImage2D(GL_TEXTURE_2D, 0, GL_R8, ww, hh, 0, GL_RED, GL_UNSIGNED_BYTE, &buffer[0]);
person user3808059    schedule 03.12.2014