renderizando texto SDL_TTF en openGL Red Square en lugar de texto
-
27-10-2019 - |
Pregunta
He intentado representar texto en una ventana openGL usando SDL y la biblioteca SDL_TTF en Windows XP, VS2010.
Versiones:
SDL versión 1.2.14
SDL TTF desarrollo 1.2.10
openGL (la versión tiene al menos 2-3 años).
He creado con éxito una ventana openGL usando SDL/SDL_image y puedo representar líneas/polígonos en ella sin problemas.
Sin embargo, al pasar al texto, parece que hay algún defecto en mi programa actual. Obtengo el siguiente resultado al intentarlo. este código aquí
Para aquellos que no estén dispuestos a pegar, aquí están solo los segmentos de código cruciales:
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 );
}
segmento 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;
}
¿Hay algún código obvio que me falta?
Gracias por cualquier ayuda sobre este tema.
He estado intentando aprender openGL y SDL durante 3 días, así que perdone cualquier información errónea de mi parte.
EDITAR:
Noto que usando
TTF_RenderUTF8_Shaded
TTF_RenderUTF8_Solid
Lanza una excepción de puntero nulo, lo que significa que hay un error dentro de la función de representación de texto real (sospecho), no sé qué significa esto. TTF_RenderUTF8_Blended
devuelve un cuadrado rojo, pero sospecho que todos los problemas dependen de esto.
Solución
Creo que el problema está en las funciones glEnable(GL_TEXTURE_2D)
y glDisable(GL_TEXTURE_2D)
que deben llamarse cada vez que se pinta el texto en la pantalla. Y quizás también la conversión de color entre la superficie SDL y GL no es correcta.
He combinado create_texture
y drawText
en una sola función que muestra el texto correctamente.Ese es el código:
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 );
}
Estoy inicializando OpenGL de la siguiente manera:
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);
}
Otros consejos
Creo que debería agregar glEnable (GL_BLEND), porque el código para la superficie del texto dice TTF_RenderUTF8_Blended (fntCourier, text, clrFg) y debe habilitar las capacidades de combinación de opengl.
EDITAR
Bien, finalmente me tomé el tiempo de pasar tu código por un compilador.Lo más importante es que el compilador con -Werror
para que las advertencias se conviertan en errores
GLuint * create_texture(SDL_Surface *surface) {
GLuint texture = 0;
/*...*/
return &texture;
}
No lo vi primero, porque es algo así como el codificador C 101 y es bastante inesperado: ¡No debes devolver punteros a variables locales!.Una vez que las funciones salen del alcance, el puntero devuelto señalará únicamente tonterías.¿Por qué devuelves un puntero?Simplemente devuelve un número entero:
GLuint create_texture(SDL_Surface *surface) {
GLuint texture = 0;
/*...*/
return texture;
}
Debido a esto, tampoco eliminarás la textura después.Lo subes a OpenGL, pero luego pierdes la referencia.
A tu código le falta un Sin embargo, su uso de texturas no es óptimo.De la forma en que lo hiciste, recreas una textura completamente nueva cada vez que estás a punto de dibujar ese texto.Si eso sucede en un bucle de animación, podrásglEnable(GL_TEXTURE_2D)
es por eso que no puedes ver ningún efecto de textura.
quedarse sin memoria de textura bastante pronto- ralentizarlo significativamente
(1) se puede solucionar al no generar un nuevo nombre de textura cada vez que se vuelve a dibujar
(2) pueden ser direcciones cargando nuevos datos de textura solo cuando el texto cambia y no usando glTexImage2D, sino glTexSubImage2D (por supuesto, si las dimensiones de la textura cambian, debe ser glTexImage2D).
EDITAR, encontré otro posible problema, pero primero solucione el problema del puntero.
Debes asegurarte de estar utilizando el modo de entorno de textura GL_REPLACE o GL_MODULATE.Si usa GL_DECAL o GL_BLEND, terminará con texto rojo en un quad rojo.
Hubo una fuga de memoria de la función en mi publicación anterior y el programa se bloqueó después de un tiempo ... Mejoré esto separando la carga de textura y la visualización:
La primera función debe llamarse antes del bucle SDL. Carga la cadena de texto en la memoria:
Cada cadena cargada debe tener un parámetro txtNum diferente
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);
}
El segundo muestra la cadena, se debe llamar en el bucle 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);
}