Поверхность плохо заполнена sdl_ttf

Я пытаюсь сделать игру openGL на С++, и я пытаюсь реализовать текстовую систему, для этого я пытаюсь использовать SDL_ttf.

Я уже использовал SDL_ttf в другом проекте, но с другим API, поэтому я сделал тот же код, но он не заполнил пиксельные данные поверхности.

Вот мой код:


void Text2Texture::setText(const char * text, size_t fontIndex){

    SDL_Color c = {255, 255, 0, 255};
    SDL_Surface * surface;

    surface = TTF_RenderUTF8_Blended(loadedFonts_[fontIndex], text, c);
    if(surface == nullptr) {
        fprintf(stderr, "Error TTF_RenderText\n");
        return;
    }    

    GLenum texture_format;
    GLint colors = surface->format->BytesPerPixel;

    if (colors == 4) {   // alpha
        if (surface->format->Rmask == 0x000000ff)
        texture_format = GL_RGBA;
        else
        texture_format = GL_BGRA_EXT;
    } else {             // no alpha
        if (surface->format->Rmask == 0x000000ff)
        texture_format = GL_RGB;
        else
        texture_format = GL_BGR_EXT;
    }


    glBindTexture(GL_TEXTURE_2D, textureId_);
    glTexImage2D(GL_TEXTURE_2D, 0, colors, surface->w, surface->h, 0, texture_format, GL_UNSIGNED_BYTE, surface->pixels);

    ///This line tell me pixel data is 8 bit witch isn't good ?
    std::cout << "pixel size : " << sizeof(surface->pixels) << std::endl;

    ///This line give me correct result
    fprintf(stderr, "texture size : %d %d\n", surface->w, surface->h);

    glBindTexture(GL_TEXTURE_2D, 0);

}

Как видно из комментария, пиксели указателя на поверхности имеют размер 8 бит, что слишком мало для текстуры. Я не знаю, почему Он это делает.

В конце данные текстуры выглядят полностью заполненными 0 (в результате получается черный отряд, использующий очень простые шейдеры).

В этом проекте я использую glfw для создания контекста openGL, поэтому я не использую sdl и не инициализировал его.

Однако я инициализировал sdl_ttf, вот все, что я сделал перед вызовом setText:


std::vector<TTF_Font *> Text2Texture::loadedFonts_;

void Text2Texture::init(){

    if(TTF_Init() == -1) {
        fprintf(stderr, "TTF_Init: %s\n", TTF_GetError());
    }

}

int Text2Texture::loadFont(std::string const& fontPath){

    loadedFonts_.emplace_back();

    loadedFonts_.back() = TTF_OpenFont(fontPath.data(), 32);

    if( loadedFonts_.back() == nullptr ) {
        fprintf(stderr, "TTF_OpenFont: %s \n", TTF_GetError());
        loadedFonts_.pop_back();
        return -1;
    }

    return ((int)loadedFonts_.size() - 1);

}

///The constructor initialize the texture :

Text2Texture::Text2Texture(){

    glGenTextures(1, &textureId_);
    glBindTexture(GL_TEXTURE_2D, textureId_);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);

}

Мой класс получил статическую часть вот это corp :


class Text2Texture {

public:

    Text2Texture();

    void setText(const char * text, size_t fontIndex = 0);

    unsigned int getId() const;

    //Partie static
    static void init();

    static void quit();

    static int loadFont(std::string const& fontPath);

private:

    unsigned int textureId_;

    //Partie static
    static std::vector<TTF_Font *> loadedFonts_;

};

Я инициализирую sdl_ttf и загружаю текстуру статическим методом, затем создаю экземпляр класса для создания конкретной текстуры.

Если вы найдете, где моя ошибка, я был бы рад прочитать ваш ответ.

(Кстати, я не совсем уверен, что использование sdl_ttf является хорошим подходом, если у вас есть идея получше, я бы тоже взял его, но я хотел бы сначала решить эту проблему)


person Jean Mathieu    schedule 14.09.2019    source источник


Ответы (1)


Параметр формата и типа glTexImage2D указывает, как кодируется один пиксель.
Когда создается текстурный шрифт, каждый пиксель кодируется в один байт. Это означает, что ваша текстура состоит из одного цветового канала, и каждый пиксель имеет 1 байт. Я очень уверен, что colors = surface->format->BytesPerPixel равно 1. Обратите внимание, что вполне достаточно закодировать глиф в одном цветовом канале, потому что глиф просто состоит из информации.

По умолчанию OpenGL предполагает, что начало каждой строки изображения выровнено по 4 байтам. Это связано с тем, что параметр GL_UNPACK_ALIGNMENT по умолчанию равен 4. . Поскольку изображение имеет 1 (КРАСНЫЙ) цветовой канал и плотно упаковано, возможно, начало строки смещено.
Измените GL_UNPACK_ALIGNMENT на 1 перед указанием двумерного изображения текстуры (glTexImage2D).

Поскольку текстура имеет только один (красный) цветовой канал, зеленый и синий цвета будут равны 0, а альфа-канал будет равен 1 при поиске текстуры. Но вы также можете обрабатывать зеленый, синий и даже альфа-канал для чтения из красного цветового канала. Этого можно добиться, установив параметры качания текстуры GL_TEXTURE_SWIZZLE_G, GL_TEXTURE_SWIZZLE_B соответственно GL_TEXTURE_SWIZZLE_A. См. glTexParameter.

Кроме того, параметр текстуры не хранится в объекте текстуры. glTexParameter изменяет объект текстуры, который в настоящее время привязан к указанной цели текущего модуля текстуры. Поэтому достаточно задать параметры один раз при создании изображения текстуры.
Для сравнения glPixelStore изменяет глобальные состояния, которые должны быть установлены на значение по умолчанию после указания изображения текстуры (если последующие вызовы glTexImage2D полагаются на него).

Спецификация 2-мерного изображения текстуры и настройка параметров могут выглядеть следующим образом:

glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
glTexImage2D(GL_TEXTURE_2D, 0, GL_R8, surface->w, surface->h, 0,
             GL_RED, GL_UNSIGNED_BYTE, surface->pixels);
glPixelStorei(GL_UNPACK_ALIGNMENT, 4);

glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_G, GL_RED);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_B, GL_RED);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_A, GL_RED);

glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
person Rabbid76    schedule 15.09.2019