我一直在尝试使用SDL和Windows XP,VS2010上的SDL_TTF库将文本渲染到openGL窗口。
版本:
SDL版本1.2.14
SDL TTF开发1.2.10
openGL(版本至少2-3岁)。
我已经使用SDL / SDL_image成功创建了一个openGL窗口,可以在没有任何问题的情况下渲染线条/多边形。
然而,转移到文本上似乎我当前的程序存在一些缺陷,我在尝试this code here时得到以下结果
对于那些不愿意在这里使用pastebin的人来说,只有重要的代码段:
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
抛出空指针异常,意味着实际文本渲染功能中存在错误(我怀疑),我不知道这意味着TTF_RenderUTF8_Blended
如何返回红色方块但我怀疑所有麻烦都归于此
答案 0 :(得分:3)
我认为问题出现在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);
}
答案 1 :(得分:2)
好的,我终于花时间把你的代码放到了编译器中。最重要的是,编译器使用-Werror
以便警告变成错误
GLuint * create_texture(SDL_Surface *surface) {
GLuint texture = 0;
/*...*/
return &texture;
}
我没有先看到它,因为这就像C编码器的101并且非常意外:你不能返回指向局部变量的指针!。一旦函数超出范围,返回的指针将仅指向无意义。你为什么要回指针?只需返回一个整数:
GLuint create_texture(SDL_Surface *surface) {
GLuint texture = 0;
/*...*/
return texture;
}
因此,您之后也不会删除纹理。您将其上传到OpenGL,但随后松开对它的引用。
你的代码错过了然而你对纹理的使用并不是最理想的。他们这样做,每次你要绘制文本时都会重新创建一个全新的纹理。如果在动画循环中发生这种情况,你将glEnable(GL_TEXTURE_2D)
,这就是为什么你看不到纹理效果的原因。
(1)可以通过不重新生成每个重绘的新纹理名称来解决
(2)可以通过仅在文本更改时上传新的纹理数据而不是使用glTexImage2D,而是glTexSubImage2D(当然,如果纹理的尺寸发生变化,则必须是glTexImage2D)。
您应确保使用GL_REPLACE或GL_MODULATE纹理环境模式。如果使用GL_DECAL或GL_BLEND,您最终会在红色四边形上显示红色文字。
答案 2 :(得分:2)
我认为你应该添加glEnable(GL_BLEND),因为文本表面的代码说TTF_RenderUTF8_Blended(fntCourier,text,clrFg),你必须启用opengl的混合功能。
答案 3 :(得分:2)
我上一篇文章中有关于该功能的泄漏记忆,程序在一段时间后崩溃了...... 我通过分离纹理加载和显示来改进它:
必须在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);
}