前段時間為了弄畢業設計,要用opengl顯示文字,在網上找了很多方法,但大都是在windows下的實現方法,幾乎沒有linux下的,找了很久才找到。
首先,opengl本身是沒有顯示文字的函數的,必須要借助其他的庫,linux下有SDL,利用SDL本身的編程是可以顯示漢字的,但是如何將opengl和SDL融合顯示漢字!這就是難點所在!
#include
#include
#include
#include
#include
#include
#define TRUE (-1)
#define FALSE 0
typedef int BOOL;
const int SCREEN_WIDTH = 600;
const int SCREEN_HEIGHT = 400;
const int SCREEN_BPP = 32;
SDL_Surface *image = NULL;
SDL_Surface *screen = NULL;
SDL_Surface *message = NULL;
TTF_Font *font = NULL;
SDL_Color textColor = { 255, 0, 0 };
SDL_Color blackColor = { 0,0,0 };
BOOL init()
{
if( SDL_Init( SDL_INIT_EVERYTHING ) == -1 )
{
return FALSE;
}
//screen = SDL_SetVideoMode( SCREEN_WIDTH, SCREEN_HEIGHT, SCREEN_BPP, SDL_SWSURFACE );
screen = SDL_SetVideoMode( SCREEN_WIDTH, SCREEN_HEIGHT, SCREEN_BPP, SDL_OPENGL );
if( screen == NULL )
{
return FALSE;
}
//Initialize SDL_ttf
if( TTF_Init() == -1 )
return FALSE;
SDL_WM_SetCaption( "show Chinese text @bluedrum", NULL );
//If everything initialized fine
return TRUE;
}
void clean_up()
{
SDL_FreeSurface( image );
SDL_FreeSurface( message );
TTF_CloseFont( font ); //Close the font that was used
TTF_Quit(); //Quit SDL_ttf
SDL_Quit(); //Quit SDL
}
SDL_Surface *load_image( char * filename )
{
SDL_Surface* loadedImage = NULL;
SDL_Surface* optimizedImage = NULL;
loadedImage = IMG_Load( filename);
if( loadedImage != NULL )
{
optimizedImage = SDL_DisplayFormat( loadedImage );
SDL_FreeSurface( loadedImage );
}
return optimizedImage;
}
void SDL_GL_Enter2DMode()
{
SDL_Surface *screen = SDL_GetVideoSurface();
/* Note, there may be other things you need to change,
depending on how you have your OpenGL state set up.
*/
glPushAttrib(GL_ENABLE_BIT);
glDisable(GL_DEPTH_TEST);
glDisable(GL_CULL_FACE);
glEnable(GL_TEXTURE_2D);
/* This allows alpha blending of 2D textures with the scene */
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glViewport(0, 0, screen->w, screen->h);
glMatrixMode(GL_PROJECTION);
glPushMatrix();
glLoadIdentity();
glOrtho(0.0, (GLdouble)screen->w, (GLdouble)screen->h, 0.0, 0.0, 1.0);
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
glLoadIdentity();
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
}
void SDL_GL_Leave2DMode()
{
glMatrixMode(GL_MODELVIEW);
glPopMatrix();
glMatrixMode(GL_PROJECTION);
glPopMatrix();
glPopAttrib();
}
/* Quick utility function for texture creation */
static int power_of_two(int input)
{
int value = 1;
while ( value < input ) {
value <<= 1;
}
return value;
}
GLuint SDL_GL_LoadTexture(SDL_Surface *surface, GLfloat *texcoord)
{
GLuint texture;
int w, h;
SDL_Surface *image;
SDL_Rect area;
Uint32 saved_flags;
Uint8 saved_alpha;
/* Use the surface width and height expanded to powers of 2 */
w = power_of_two(surface->w);
h = power_of_two(surface->h);
texcoord[0] = 0.0f; /* Min X */
texcoord[1] = 0.0f; /* Min Y */
texcoord[2] = (GLfloat)surface->w / w; /* Max X */
texcoord[3] = (GLfloat)surface->h / h; /* Max Y */
image = SDL_CreateRGBSurface(
SDL_SWSURFACE,
w, h,
32,
#if SDL_BYTEORDER == SDL_LIL_ENDIAN /* OpenGL RGBA masks */
0x000000FF,
0x0000FF00,
0x00FF0000,
0xFF000000
#else
0xFF000000,
0x00FF0000,
0x0000FF00,
0x000000FF
#endif
);
if ( image == NULL ) {
return 0;
}
/* Save the alpha blending attributes */
saved_flags = surface->flags&(SDL_SRCALPHA|SDL_RLEACCELOK);
#if SDL_VERSION_ATLEAST(1, 3, 0)
SDL_GetSurfaceAlphaMod(surface, &saved_alpha);
SDL_SetSurfaceAlphaMod(surface, 0xFF);
#else
saved_alpha = surface->format->alpha;
if ( (saved_flags & SDL_SRCALPHA) == SDL_SRCALPHA ) {
SDL_SetAlpha(surface, 0, 0);
}
#endif
/* Copy the surface into the GL texture image */
area.x = 0;
area.y = 0;
area.w = surface->w;
area.h = surface->h;
SDL_BlitSurface(surface, &area, image, &area);
/* Restore the alpha blending attributes */
#if SDL_VERSION_ATLEAST(1, 3, 0)
SDL_SetSurfaceAlphaMod(surface, saved_alpha);
#else
if ( (saved_flags & SDL_SRCALPHA) == SDL_SRCALPHA ) {
SDL_SetAlpha(surface, saved_flags, saved_alpha);
}
#endif
/* Create an OpenGL texture for the image */
glGenTextures(1, &texture);
glBindTexture(GL_TEXTURE_2D, texture);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexImage2D(GL_TEXTURE_2D,
0,
GL_RGBA,
w, h,
0,
GL_RGBA,
GL_UNSIGNED_BYTE,
image->pixels);
SDL_FreeSurface(image); /* No longer needed */
return texture;
}
int main(int argc,char * argv[])
{
char a[] = "abc";
char *img_name = "./bk.jpg";
Uint16 msg[1024] = {0xc2d0,0xcbce,0xcce5,0};
wchar_t *msg1 = L"新宋體";
int w,h,done;
int i=0;
GLuint texture;
GLfloat texcoord[4];
GLfloat texMinX, texMinY;
GLfloat texMaxX, texMaxY;
SDL_Event event;
//msg2 = ConvertUnicodeToUtf8(msg1);
init();
if(argc > 1)
{
strncpy(img_name,argv[1],sizeof(img_name)-1);
img_name[sizeof(img_name)-1] = 0;
}
font = TTF_OpenFont("./simfang.ttf",20);
if(font == NULL)
{
fprintf(stderr,"font open failure %s\n",SDL_GetError());
clean_up();
exit(-1);
}
image =load_image(img_name);
TTF_SetFontStyle(font,TTF_STYLE_BOLD | TTF_STYLE_ITALIC);
message = TTF_RenderUNICODE_Solid( font, msg1, textColor );
//message = TTF_RenderText_Solid(font,"ABCEFGHIJK",blackColor);
w = message->w;
h = message->h;
//w = image->w;
//h = image->h;
texture = SDL_GL_LoadTexture(message, texcoord);
/* Make texture coordinates easy to understand */
texMinX = texcoord[0];
texMinY = texcoord[1];
texMaxX = texcoord[2];
texMaxY = texcoord[3];
/* Initialize the GL state */
glViewport( 0, 0, screen->w, screen->h );
glMatrixMode( GL_PROJECTION );
glLoadIdentity( );
glOrtho( -2.0, 2.0, -2.0, 2.0, -20.0, 20.0 );
glMatrixMode( GL_MODELVIEW );
glLoadIdentity( );
glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_LESS);
glShadeModel(GL_SMOOTH);
/* Clear the screen */
glClearColor(1.0, 1.0, 1.0, 1.0);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
/* Show the text on the screen 關鍵部分*/
SDL_GL_Enter2DMode();
glBindTexture(GL_TEXTURE_2D, texture);
glBegin(GL_TRIANGLE_STRIP);
glTexCoord2f(texMinX, texMinY); glVertex2i(50, 50 );
glTexCoord2f(texMaxX, texMinY); glVertex2i(50+w, 50 );
glTexCoord2f(texMinX, texMaxY); glVertex2i(50, 50+h);
glTexCoord2f(texMaxX, texMaxY); glVertex2i(50+w, 50+h);
glEnd();
SDL_GL_Leave2DMode();
SDL_GL_SwapBuffers( );
if(SDL_Flip(screen) == -1)
return -1;
/* Wait for a keystroke,input esc to quit */
done = 0;
while ( ! done ) {
while ( SDL_PollEvent(&event) ) {
switch (event.type) {
case SDL_KEYDOWN:
case SDL_QUIT:
done = 1;
break;
default:
break;
}
}
}
//SDL_Delay(3000);
clean_up();
}
編譯用gcc test.c -o test -lSDL_image -lSDL_ttf -lglut -finput-charset='gbk' -fshort-wchar
前面幾個參數是調用庫, -finput-charset='gbk' -fshort-wchar參數是為了解決漢字的編碼問題
其中bk.jpg是圖片文件./simfang.tff是漢字庫,可以在網上下。
代碼分析,與其它的opengl函數使用來說就多了幾個函數,SDL_GL_LoadTexture;SDL_GL_Enter2DMode;SDL_GL_Leave2DMode這3個函數,它們是實現漢字顯示的關鍵函數,函數之間相互獨立,可以拷過去直接用。其根本原理還是使用了opengl的紋理映射的原理;圖片和漢字的用法也是一樣的。PS:前面做的時候,看到過中科院一個碩士的方法,看了半天論文也沒發現具體的實現方法,汗!!最后還是在SDL的官方文件中找到,再自己研究的方法。
opengl和SDL的融合還是在 SDL_SetVideoMode( SCREEN_WIDTH, SCREEN_HEIGHT, SCREEN_BPP, SDL_OPENGL )中的SDL_OPENGL宏,否則就是SDL的顯示了。如果能用SDL加opengl來作界面和游戲的話,還是很給力的。