说到图形界面编程,想到的大多是Windows下的多种多样的应用程序。Linux是一个基于命令行的操作系统,在Linux下的工作大多是在命令行里完成的,而并非像Windows那样。图形界面虽然并不是Linux的一部分,我们通过一些工具,依然可以编写一些在Linux下的图形应用程序。
OpenGL是一个工业标准的三维计算机图形软件接口,它由SGI公司发布并广泛应用于Unix、OS/2、Windows/NT等多种平台,这其中当然也包括Linux。
X11也叫做X Window系统,X Window系统 (X11或X)是一种位图显示的 视窗系统 。它是在 Unix 和 类Unix操作系统,以及 OpenVMS 上建立图形用户界面的标准工具包和协议。Linux就是一个类Unix的操作系统。
有了这两个工具,我们便能在Linux下进行图形界面编程了。
由于X Window系统的协议和架构 X基于 客户端-服务器 模型,首先创建一个连接,连接到X服务器。
dpy = XOpenDisplay(NULL); if (dpy == NULL) fatalError("could not open display");
对于X窗口系统来说,它所使用的OpenGL扩展是作为OpenGL的一个附件提供的,所以还需要检测X服务器是否是支持OpenGL扩展。
if(!glXQueryExtension(dpy, &dummy, &dummy)) fatalError("X server has no OpenGL GLX extension");
接下来就是给窗口找到一个合适的视觉样式。比如有些支持双缓冲,有些不支持,etc。
vi = glXChooseVisual(dpy, DefaultScreen(dpy), dblBuf); if (vi == NULL) { vi = glXChooseVisual(dpy, DefaultScreen(dpy), snglBuf); if (vi == NULL) fatalError("no RGB visual with depth buffer"); glf_DoubleBuffer = GL_FALSE; } if(vi->class != TrueColor) fatalError("TrueColor visual required for this program");
接着创建一个OpenGL状态信息,等一下创建窗口会用到。
cx = glXCreateContext(dpy, vi, None, GL_TRUE); if (cx == NULL) fatalError("could not create rendering context");
调用XCreateWindow函数,使用刚刚指定的视觉样式创建窗口。
cmap = XCreateColormap(dpy, RootWindow(dpy, vi->screen), vi->visual, AllocNone); swa.colormap = cmap; swa.border_pixel = 0; swa.event_mask = KeyPressMask | ExposureMask | ButtonPressMask | StructureNotifyMask; win = XCreateWindow(dpy, RootWindow(dpy, vi->screen), 0, 0, glf_WinWidth, glf_WinHeight, 0, vi->depth, InputOutput, vi->visual, CWBorderPixel | CWColormap | CWEventMask, &swa); XSetStandardProperties(dpy, win, "main", "main", None, argv, argc, NULL);
再将刚刚创建的OpenGL状态信息,绑定到窗口。
glXMakeCurrent(dpy, win, cx);
最后,调用XMapWindow函数将窗口显示在桌面上就完成了。
XMapWindow(dpy, win);
void glfInit() { glViewport(0, 0, glf_WinWidth, glf_WinHeight); glMatrixMode(GL_PROJECTION); glLoadIdentity(); glf_left=0.0f; glf_right=50.0f; glf_bottom=0.0f; glf_top=50.0f; glf_near=-1.0f; glf_far=1.0f; glOrtho(glf_left,glf_right,glf_bottom,glf_top,glf_near,glf_far); glMatrixMode(GL_MODELVIEW); }
if (needUpdate) { glfUpdate(); //glFrame更新 needUpdate = GL_FALSE; needDraw = GL_TRUE; } if (needDraw) { glfDraw(); //glFrame绘制 needDraw = GL_FALSE; }
glRasterPos2i(label.posx,label.posy); printString(label.str);
struct Label { GLboolean isShow; //是否显示 char str[100]; //显示的内容 GLint posx; //光栅位置x GLint posy; //光栅位置y GLfloat color[4]; //颜色 };以及绘制标签的函数GLboolean glfDrawLabel(Label label)
GLboolean glfDrawLabel(Label label) { if (label.isShow == GL_FALSE) return GL_FALSE; glPushAttrib(GL_CURRENT_BIT); glColor3fv(label.color); glRasterPos2i(label.posx,label.posy); printString(label.str); glPopAttrib(); return GL_TRUE; }对于按钮来说,当一个页面里面有很多按钮时,glFrame需要知道是那一个按钮被按下了,从而进行对应的操作。于是定义一个全局变量
struct Button { GLboolean isAround; GLfloat aroundColor[4]; GLint aroundLineWidth; GLboolean isShow; Label text; Point2D leftDown; Point2D leftUp; Point2D rightDown; Point2D rightUp; GLfloat color[4]; ButtonEvent event[10]; };以及按钮的摁下检测函数
GLboolean glfCheckButtonPress(int ix,int iy,Button button) { double x,y; iy=glf_WinHeight-iy; //将鼠标的位置坐标转化为OpenGL坐标系中 x=(double)ix/(double)glf_WinWidth*(glf_right-glf_left); //把坐标转化到视景体中 y=(double)iy/(double)glf_WinHeight*(glf_right-glf_left); //把坐标转化到视景体中 if (x <= button.rightDown.p[0] && x >= button.leftDown.p[0] && y <= button.rightUp.p[1] && y >= button.rightDown.p[1]) { strcpy(glf_buttonevent,button.event); return GL_TRUE; } return GL_FALSE; }
GLboolean glfDrawButton(Button button) { if (button.isShow == GL_FALSE) return GL_FALSE; glPushAttrib(GL_CURRENT_BIT); glColor3fv(button.color); glBegin(GL_QUADS); glVertex2fv(button.leftDown.p); glVertex2fv(button.leftUp.p); glVertex2fv(button.rightUp.p); glVertex2fv(button.rightDown.p); glEnd(); glfDrawLabel(button.text); if (button.isAround == GL_TRUE) { glColor3fv(button.aroundColor); glLineWidth(button.aroundLineWidth); glBegin(GL_LINES); glVertex2fv(button.rightDown.p); glVertex2fv(button.leftDown.p); glEnd(); glBegin(GL_LINES); glVertex2fv(button.leftDown.p); glVertex2fv(button.leftUp.p); glEnd(); glBegin(GL_LINES); glVertex2fv(button.leftUp.p); glVertex2fv(button.rightUp.p); glEnd(); glBegin(GL_LINES); glVertex2fv(button.rightUp.p); glVertex2fv(button.rightDown.p); glEnd(); } glPopAttrib(); return GL_TRUE; }
#ifndef GLFRAME_H_INCLUDED #define GLFRAME_H_INCLUDED #include "global.h" #include "font.h" #include "Label.h" #include "Button.h" void glfPrint(GLboolean doubleBuffer); void glfInit(); void glfProcessKeyboard(KeySym keysym); void glfProcessMouseClick(int x,int y); void glfprocessButtonPress(); void glfUpdate(); void glfReshape(int width,int height); void glfDraw(); Label label; Button button; Button b_exit; void glfPrint(GLboolean doubleBuffer) { if (doubleBuffer) glXSwapBuffers(dpy, win); else glFlush(); } void glfInit() { glViewport(0, 0, glf_WinWidth, glf_WinHeight); glMatrixMode(GL_PROJECTION); glLoadIdentity(); glf_left=0.0f; glf_right=50.0f; glf_bottom=0.0f; glf_top=50.0f; glf_near=-1.0f; glf_far=1.0f; glOrtho(glf_left,glf_right,glf_bottom,glf_top,glf_near,glf_far); glMatrixMode(GL_MODELVIEW); makeRasterFont(); label.isShow=GL_TRUE; label.color[0]=1.0f; label.color[1]=1.0f; label.color[2]=0.0f; label.color[3]=0.0f; label.posx=15; label.posy=40; strcpy(label.str,"HELLO SSSOGS"); button.isShow=GL_TRUE; button.isAround=GL_TRUE; button.aroundLineWidth=3; button.aroundColor[0]=0.0f; button.aroundColor[1]=1.0f; button.aroundColor[2]=0.0f; button.aroundColor[3]=0.0f; button.leftDown.p[0]=4; button.leftDown.p[1]=20; button.leftUp.p[0]=4; button.leftUp.p[1]=30; button.rightDown.p[0]=24; button.rightDown.p[1]=20; button.rightUp.p[0]=24; button.rightUp.p[1]=30; button.color[0]=0.9f; button.color[1]=0.5f; button.color[2]=0.9f; button.color[3]=0.0f; button.text.isShow=GL_TRUE; button.text.color[0]=0.0f; button.text.color[1]=0.0f; button.text.color[2]=0.0f; button.text.color[3]=0.0f; button.text.posx=6; button.text.posy=25; strcpy(button.text.str,"HIDE WORDS"); strcpy(button.event,"Test"); b_exit.isShow=GL_TRUE; b_exit.isAround=GL_TRUE; b_exit.aroundLineWidth=3; b_exit.aroundColor[0]=0.0f; b_exit.aroundColor[1]=1.0f; b_exit.aroundColor[2]=0.0f; b_exit.aroundColor[3]=0.0f; b_exit.leftDown.p[0]=26; b_exit.leftDown.p[1]=20; b_exit.leftUp.p[0]=26; b_exit.leftUp.p[1]=30; b_exit.rightDown.p[0]=46; b_exit.rightDown.p[1]=20; b_exit.rightUp.p[0]=46; b_exit.rightUp.p[1]=30; b_exit.color[0]=0.9f; b_exit.color[1]=0.5f; b_exit.color[2]=0.9f; b_exit.color[3]=0.0f; b_exit.text.isShow=GL_TRUE; b_exit.text.color[0]=0.0f; b_exit.text.color[1]=0.0f; b_exit.text.color[2]=0.0f; b_exit.text.color[3]=0.0f; b_exit.text.posx=28; b_exit.text.posy=25; strcpy(b_exit.text.str,"EXIT"); strcpy(b_exit.event,"exit"); } void glfProcessKeyboard(KeySym keysym) { if (keysym == (KeySym)XK_Escape) exit(0); } void glfProcessMousePress(int x,int y) { if (glfCheckButtonPress(x,y,button) == GL_TRUE) { glfprocessButtonPress(); } if (glfCheckButtonPress(x,y,b_exit) == GL_TRUE) { glfprocessButtonPress(); } } void glfprocessButtonPress() { if (glf_buttonevent == NULL) return ; if (strcmp(glf_buttonevent,"Test") == 0) { label.isShow=!label.isShow; if (label.isShow) { strcpy(button.text.str,"HIDE WORDS"); } else { strcpy(button.text.str,"SHOW WORDS"); } } if (strcmp(glf_buttonevent,"exit") == 0) { exit(0); } } void glfUpdate() { } void glfReshape(int width,int height) { glf_WinWidth=width; glf_WinHeight=height; glViewport(0,0,glf_WinWidth,glf_WinHeight); } void glfDraw() { glClearColor(0.0,0.0,0.0,0.0); glClear(GL_COLOR_BUFFER_BIT); glfDrawLabel(label); glfDrawButton(button); glfDrawButton(b_exit); glfPrint(glf_DoubleBuffer); } #endif // GLFRAME_H_INCLUDED