рендеринг текста SDL_TTF на openGL Red Square вместо текста - PullRequest
1 голос
/ 20 октября 2011

Я пытался визуализировать текст в окне openGL, используя SDL и библиотеку SDL_TTF в Windows XP, VS2010.
Версии:
SDL версия 1.2.14
SDL TTF devel 1.2.10
openGL (версии не менее 2-3 лет).

Я успешно создал окно openGL с использованием SDL / SDL_image и могу без проблем отображать на нем линии / многоугольники.

Однако, переходя к тексту, кажется, что в моей текущей программе есть какой-то недостаток, и я пытаюсь получить следующий результат при попытке этот код здесь

enter image description here

дляте, кто не хочет вставлять здесь, являются только ключевыми сегментами кода:

void drawText(char * text) {
    glLoadIdentity();
    SDL_Color clrFg = {0,0,255,0}; // set colour to blue (or 'red' for BGRA)
    SDL_Surface *sText = TTF_RenderUTF8_Blended( fntCourier, text, clrFg );
    GLuint * texture = create_texture(sText);
    glBindTexture(GL_TEXTURE_2D, *texture);
    // draw a polygon and map the texture to it, may be the source of error
    glBegin(GL_QUADS); {
        glTexCoord2i(0, 0); glVertex3f(0, 0, 0);
        glTexCoord2i(1, 0); glVertex3f(0 + sText->w, 0, 0);
        glTexCoord2i(1, 1); glVertex3f(0 + sText->w, 0 + sText->h, 0);
        glTexCoord2i(0, 1); glVertex3f(0, 0 + sText->h, 0);
    } glEnd();
    // free the surface and texture, removing this code has no effect
    SDL_FreeSurface( sText );
    glDeleteTextures( 1, texture );
}

сегмент 2:

// create GLTexture out of SDL_Surface
GLuint * create_texture(SDL_Surface *surface) {
    GLuint texture = 0;

    glGenTextures(1, &texture);
    glBindTexture(GL_TEXTURE_2D, texture);
    // The SDL_Surface appears to have BGR_A formatting, however this ends up with a 
    // white rectangle no matter which colour i set in the previous code.
    int Mode = GL_RGB;

    if(surface->format->BytesPerPixel == 4) {
        Mode = GL_RGBA;
    }

    glTexImage2D(GL_TEXTURE_2D, 0, Mode, surface->w, surface->h, 0, Mode, 
                 GL_UNSIGNED_BYTE, surface->pixels);

    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

    return &texture;
}

Есть ли очевидный фрагмент кода, который мне не хватает?
Спасибоза любую помощь по этому вопросу.
Я пытаюсь изучать openGL и SDL уже 3 дня, поэтому, пожалуйста, прости любую дезинформацию с моей стороны.


РЕДАКТИРОВАТЬ:

Я заметил, что используя
TTF_RenderUTF8_Shaded
TTF_RenderUTF8_Solid

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

Ответы [ 4 ]

3 голосов
/ 05 декабря 2011

Я думаю, что проблема в функциях glEnable(GL_TEXTURE_2D) и glDisable(GL_TEXTURE_2D), которые должны вызываться каждый раз, когда текст отображается на экране. И, возможно, преобразование цвета между поверхностями SDL и GL не так. Я объединил create_texture и drawText в одну функцию, которая правильно отображает текст. Вот код:

void drawText(char * text, TTF_Font* tmpfont) {
SDL_Rect area;
SDL_Color clrFg = {0,0,255,0};
SDL_Surface *sText = SDL_DisplayFormatAlpha(TTF_RenderUTF8_Blended( tmpfont, text, clrFg ));
area.x = 0;area.y = 0;area.w = sText->w;area.h = sText->h;
SDL_Surface* temp = SDL_CreateRGBSurface(SDL_HWSURFACE|SDL_SRCALPHA,sText->w,sText->h,32,0x000000ff,0x0000ff00,0x00ff0000,0x000000ff);
SDL_BlitSurface(sText, &area, temp, NULL);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, sText->w, sText->h, 0, GL_RGBA, GL_UNSIGNED_BYTE, temp->pixels);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
glEnable(GL_TEXTURE_2D);
glBegin(GL_QUADS); {
    glTexCoord2d(0, 0); glVertex3f(0, 0, 0);
    glTexCoord2d(1, 0); glVertex3f(0 + sText->w, 0, 0);
    glTexCoord2d(1, 1); glVertex3f(0 + sText->w, 0 + sText->h, 0);
    glTexCoord2d(0, 1); glVertex3f(0, 0 + sText->h, 0); 
} glEnd();
glDisable(GL_TEXTURE_2D);
SDL_FreeSurface( sText );
SDL_FreeSurface( temp );
} 

Скриншот

Я инициализирую OpenGL следующим образом:

int Init(){
glClearColor( 0.1, 0.2, 0.2, 1);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho( 0, 600, 300, 0, -1, 1 );
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
if( glGetError() != GL_NO_ERROR ){
    return false;
}
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_COLOR, GL_ONE_MINUS_SRC_ALPHA);
} 
2 голосов
/ 05 декабря 2011

В моем предыдущем посте произошла утечка памяти функции, и через некоторое время программа зависала ... Я улучшил это, разделив загрузку и отображение текстуры:

Первая функция должна быть вызвана доцикл SDL. Он загружает текстовую строку в память:

Каждая загруженная строка должна иметь различный параметр txtNum

GLuint texture[100];
SDL_Rect area[100]; 
void Load_string(char * text, SDL_Color clr, int txtNum, const char* file, int ptsize){
    TTF_Font* tmpfont;
    tmpfont = TTF_OpenFont(file, ptsize); 
    SDL_Surface *sText = SDL_DisplayFormatAlpha(TTF_RenderUTF8_Solid( tmpfont, text, clr ));
    area[txtNum].x = 0;area[txtNum].y = 0;area[txtNum].w = sText->w;area[txtNum].h = sText->h;
    glGenTextures(1, &texture[txtNum]);
    glBindTexture(GL_TEXTURE_2D, texture[txtNum]);
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, sText->w, sText->h, 0, GL_BGRA, GL_UNSIGNED_BYTE, sText->pixels);
    glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
    SDL_FreeSurface( sText );
    TTF_CloseFont(tmpfont);
 }

Вторая отображает строку, должна вызываться в цикле SDL:

void drawText(float coords[3], int txtNum) {
     glBindTexture(GL_TEXTURE_2D, texture[txtNum]);
     glEnable(GL_TEXTURE_2D);
     glBegin(GL_QUADS); {
     glTexCoord2f(0, 0); glVertex3f(coords[0], coords[1], coords[2]);
     glTexCoord2f(1, 0); glVertex3f(coords[0] + area[txtNum].w, coords[1], coords[2]);
     glTexCoord2f(1, 1); glVertex3f(coords[0] + area[txtNum].w, coords[1] + area[txtNum].h, coords[2]);
     glTexCoord2f(0, 1); glVertex3f(coords[0], coords[1] + area[txtNum].h, coords[2]); 
     } glEnd();
     glDisable(GL_TEXTURE_2D);
}

enter image description here

2 голосов
/ 20 октября 2011

Я думаю, вам нужно просто добавить glEnable (GL_BLEND), потому что код для текстовой поверхности говорит TTF_RenderUTF8_Blended (fntCourier, text, clrFg), и вы должны включить возможности смешивания opengl.

2 голосов
/ 20 октября 2011

EDIT

Хорошо, я наконец-то нашел время, чтобы поставить ваш код через компилятор. Самое главное, компилятор с -Werror, чтобы предупреждение превращалось в ошибки

GLuint * create_texture(SDL_Surface *surface) {
    GLuint texture = 0;

    /*...*/

    return &texture;
}

Сначала я его не видел, потому что это что-то вроде 101 кодера C и довольно неожиданно: Вы не должны возвращать указатели на локальные переменные! . Как только функции выйдут из области видимости, возвращаемый указатель будет указывать только на бессмыслицу. Почему вы вообще возвращаете указатель? Просто верните целое число:

GLuint create_texture(SDL_Surface *surface) {
    GLuint texture = 0;

    /*...*/

    return texture;
}

Из-за этого вы также не собираетесь удалять текстуру позже. Вы загружаете его в OpenGL, но затем теряете ссылку на него.


Ваш код пропускает glEnable(GL_TEXTURE_2D), поэтому вы не можете видеть никаких эффектов текстуры. Однако использование текстур является неоптимальным. Так, как вы это сделали, вы воссоздаете совершенно новую текстуру каждый раз, когда собираетесь нарисовать этот текст. Если это произойдет в цикле анимации, вы

  1. довольно скоро закончится память текстур
  2. значительно замедлить

(1) можно устранить, не генерируя новое имя текстуры каждый перерисовывая

(2) можно адресовать, загружая новые данные текстуры только при изменении текста и не используя glTexImage2D, но glTexSubImage2D (конечно, если размеры текстуры изменяются, это должен быть glTexImage2D).


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

Вы должны убедиться, что используете режим текстурной среды GL_REPLACE или GL_MODULATE. Если вы используете GL_DECAL или GL_BLEND, вы получите красный текст на красном квадре.

...