Сгенерированные глифы из FreeType, содержащие сегменты памяти - PullRequest
2 голосов
/ 10 ноября 2019

При реализации рендеринга текста в моем игровом движке с использованием FreeType (2.10.1) я сталкиваюсь со странно выглядящими глифами, в которых буква повторяется четыре раза, отражается по оси x и переворачивается вверх ногами.

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

Это то, что я получаю, когда пытаюсь отобразитьслово "сфинкс" .

The word 'sphinx'

Вот пример полного предложения "сфинкс из черного кварца, суди мою клятву" перевернул горизонтальнои повернул на 180 градусов.

Example sentence, flipped horizontally and rotated 180 degrees


Я скомпилировал этот код , чтобы исключить моя среда MinGW ошибочна .

Я уверен, что мое использование OpenGL не является проблемой, так как мой код загрузки текстур и рендеринга работает для других изображений.

В настоящее время я упаковываю важные биты FT_Glyph_Slot в структуру с именем Letter и кеширую эту структуру. Удаление обтекания и кэширования не устранило ошибку.


Вот соответствующие фрагменты кода:

Инициализация FreeType.

// src/library/services/graphics/font/FreeType.cpp

void FreeType::initialize() {
    Logger::info("Initializing FreeType");

    if (FT_Init_FreeType(&m_library)) {
        Logger::error("Could not initialize FreeType");

        return;
    }
}

void FreeType::useFont(const std::string& fontName, const unsigned int fontSize = 42) {
    Logger::info("Loading font " + fontName);

    if (FT_New_Face(m_library, fontName.c_str(), 0, &m_currentFace)) {
        Logger::error("Could not open font " + fontName);

        return;
    }

    FT_Set_Pixel_Sizes(m_currentFace, 0, fontSize);
}

Код, использующий FreeType длясоздать Letter.

// src/library/services/graphics/font/FreeType.cpp

std::shared_ptr<Letter> FreeType::getLetter(unsigned long character) {
    // Try loading from cache
    if (std::shared_ptr<Letter> letter = m_letters.get(std::to_string(character))) {
        return letter;
    }

    return loadLetter(character);
}

std::shared_ptr<Letter> FreeType::loadLetter(unsigned long character) {
    if (FT_Load_Char(m_currentFace, character, FT_LOAD_RENDER)) {
        Logger::error("Could not load character " + std::string(1, character));

        return std::shared_ptr<Letter>();
    }

    FT_GlyphSlot& glyph = m_currentFace->glyph;

    Letter letter = {
            .id = character,
            .textureId = 0,
            .bitmap = {
                    .buffer = glyph->bitmap.buffer,
                    .width = glyph->bitmap.width,
                    .height = glyph->bitmap.rows
            },
            .offset = {
                    .x = glyph->bitmap_left,
                    .y = glyph->bitmap_top
            },
            .advance = {
                    .x = glyph->advance.x,
                    .y = glyph->advance.y
            }
    };

    std::shared_ptr<Letter> sharedLetter = std::make_shared<Letter>(letter);

    cache(sharedLetter);

    return sharedLetter;
}

void FreeType::cache(std::shared_ptr<Letter> letter) {
    m_letters.add(std::to_string(letter->id), letter);
}

Графическая система, инициализирующая FreeType

// src/library/services/graphics/opengl/OpenGLGraphics.cpp

void OpenGLGraphics::initialize(int windowWidth, int windowHeight) {
    // ... OpenGL initialization

    m_freeType.initialize();
    m_freeType.useFont("../../../src/library/assets/fonts/OpenSans-Regular.ttf");
}

Код, получающий Letter в текстовом редакторе.

// src/library/services/graphics/opengl/OpenGLGraphics.cpp

void OpenGLGraphics::drawText(const std::string &text, Vector2f location) {
    for (auto iterator = text.begin(); iterator < text.end(); ++iterator) {
        std::shared_ptr<Letter> letter = m_freeType.getLetter(*iterator);

        if (!letter->textureId) {
            std::shared_ptr<Texture> tex = 
                ImageLoader::loadFromCharArray(
                    letter->bitmap.buffer, 
                    letter->bitmap.width, 
                    letter->bitmap.height
                );

            letter->textureId = tex->id;
            m_freeType.cache(letter);
        }

    // ... OpenGL text rendering
    }
}

Код для генерации Texture из bitmap->buffer.

// src/library/services/graphics/opengl/util/ImageLoader.cpp

std::shared_ptr<Texture>
ImageLoader::loadFromCharArray(const unsigned char *image, const unsigned int width, const unsigned int height) {
    std::shared_ptr<Texture> texture = std::make_shared<Texture>();

    texture->width = width;
    texture->height = height;

    glGenTextures(1, &texture->id);

    glBindTexture(GL_TEXTURE_2D, texture->id);

    glPixelStorei(GL_UNPACK_ALIGNMENT, 1);

    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, (GLsizei) width, (GLsizei) height, 0, GL_RGBA, GL_UNSIGNED_BYTE, image);

    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_MAG_FILTER, GL_NEAREST);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);

    glGenerateMipmap(GL_TEXTURE_2D);

    glBindTexture(GL_TEXTURE_2D, 0);

    return texture;
}

Если предоставленных фрагментов кода не должно быть достаточно, я с удовольствием добавлю еще. Этот проект с открытым исходным кодом и доступен здесь, на GitHub .

1 Ответ

1 голос
/ 10 ноября 2019

Вы предполагаете, что FreeType всегда генерирует изображения RGBA с 8 битами на канал, но это не так.

Вам необходимо проверить bitmap.pixel_mode, чтобы увидеть, какой у вас формат изображения.

Обычно это будет либо FT_PIXEL_MODE_GRAY, что означает 8-битный пиксель в оттенках серого, либо FT_PIXEL_MODE_MONO, что означает 1-битный пиксель монохромный.

См. руководство для более подробной информации.

...