GLUT 這是一套 OpenGL 的輔助函數庫,他使我們能十分簡單的設置各種消息處理函數,而且與平臺無關,也就是說如果使用glut 在windows 下編譯通過的程序無需更改便可在 Linux, 和 Mac OS 下的編譯運行,這一點是十分有用的,要知道 Win32 API 繁瑣的代碼走出了 Windows 的窗戶可什麼也幹不了。給 GLUT 作了這麼多廣告,讓我們看看他是怎麼用的。
GLUT的基本功能
包括窗口初始化功能、事件處理、窗口和菜單管理、回調函數註冊和幾何建模功能。
窗口初始化功能,它有4個函數。主要用於處理初始化並以及命令行參數,初始化顯示模式,指定窗口左上角在屏幕上的位置和窗口大小,以像素爲單位。
事件處理只有一個函數,它用於顯示創建的窗口、處理輸入的事件、觸發回調函數、進入循環直到程序退出。
窗口管理包含18個函數,用於建立、銷燬窗口及可能的子窗口,管理和設置窗口的屬性。
在GLUT中有20個回調函數,用於響應用戶事件。最重要的回調函數是glutDisplayFunc,當GLUT認爲需要重新顯示窗口內容時,都將執行這一函數註冊的回調函數。另外一些重要的回調函數註冊函數有:函數glutRe-shapeFunc用於註冊窗口大小改變這一事件發生時GLUT將調用的函數。glutKeyboardFunc和glutMouseFunc用於註冊鍵盤和鼠標事件發生時的回調函數。函數glutMotionFunc註冊鼠標移動事件的回調函數。這3個函數用於人機交互處理。在沒有其他事件處理時,GLUT將調用函數glutldleFunc註冊的函數,而函數glutTimerFunc則註冊處理定時器事件的函數。
OpenGL繪圖函數只能生成點、直線、多邊形等簡單的幾何圖元,GLUT提供了18個創建三維物體的函數。利用它們可以創建9種三維物體,如圓錐體、立方體、球體等,每一物體有線框和實體2種方式。
我們看到的以glut 開頭的函數都是 glut 庫的一部分,如處理參數的,和設置窗口的,我們在這裏主要討論 GLUT 支持的各種消息處理
一:窗口更新的處理函數:
① 我們知道各種窗口的操作都會引發窗口更新消息,在glut中我們通過
void glutDisplayFunc(void (*func)(void))
來設置窗口刷新的消息處理函數,其唯一的參數指定了屏幕刷新時會調用的函數。
② 如果要處理窗口變化的消息我們可以通過設置下面函數來實現
void glutReshapeFunc(void (*func)(int w, int h))
這裏的func爲回調函數,w,h分別爲改變後窗口的寬和高。
二:對於鍵盤和鼠標的輸入我們可以通過下面兩個函數來設置:
void glutKeyboardFunc(void (*func)(unsigned char key, int x, int y))
void glutMouseFunc(void (*func)(int button, int state, int x, int y))
key 爲鍵盤按鍵的ASCII 碼
x y 都表示鼠標的位置,
而button則爲GLUT_LEFT_BUTTON或GLUT_RIGHT_BUTTON
分別表示左右按鍵。
state爲按鍵的狀態,若爲按下則爲GLUT_DOWN
當鼠標移動式我們還可以通過下面的函數來設置鼠標移動消息的處理函數
void glutMotionFunc(void (*func)(int x, int y))
X、Y分別爲鼠標的位置
三特殊函數用於完成循環畫圖(或者說是動畫)
這裏還有一個函數比較特殊
void glutIdleFunc(void (*func)(void))
這裏設置的是系統空閒時將會調用的函數
下面我們將看到一個完整的例子,通過輸入來控制三維物體的旋轉
#include <math.h>
#include <gl/glut.h>
#include <gl/gl.h>
bool mouseisdown=false;
bool loopr=false;
int mx,my;
int ry=30;
int rx=30;
void timer(int p)
{
ry-=5;
glutPostRedisplay(); //marks the current window as needing to be redisplayed.
if (loopr)
glutTimerFunc(200,timer,0);
}
void mouse(int button, int state, int x, int y)
{
if(button == GLUT_LEFT_BUTTON)
{
if(state == GLUT_DOWN)
{
mouseisdown=true;
loopr=false;
}
else
mouseisdown=false;
}
if (button== GLUT_RIGHT_BUTTON)
if(state == GLUT_DOWN)
{
loopr=true;
glutTimerFunc(200,timer,0);
}
}
void motion(int x, int y)
{
if(mouseisdown==true)
{
ry+=x-mx;
rx+=y-my;
mx=x;
my=y;
glutPostRedisplay();
}
}
void special(int key, int x, int y)
{
switch(key)
{
case GLUT_KEY_LEFT:
ry-=5;
glutPostRedisplay();
break;
case GLUT_KEY_RIGHT:
ry+=5;
glutPostRedisplay();
break;
case GLUT_KEY_UP:
rx+=5;
glutPostRedisplay();
break;
case GLUT_KEY_DOWN:
rx-=5;
glutPostRedisplay();
break;
}
}
void display()
{
float red[3]={1,0,0};
float blue[3]={0,1,0};
float green[3]={0,0,1};
float yellow[3]={1,1,0};
glClearColor(1,1,1,1);
glClear(GL_COLOR_BUFFER_BIT);
glLoadIdentity();
glRotatef(ry,0,1,0);
glRotatef(rx,1,0,0);
glColor3fv(green);
glutWireTeapot(0.5);
//glutSolidTeapot(0.5);
glFlush();
}
int main(int argc, char** argv)
{
glutInit(&argc, argv);
glutInitDisplayMode (GLUT_SINGLE| GLUT_RGBA);
glutInitWindowSize (400, 400);
glutInitWindowPosition(100,100);
glutCreateWindow ("A TEAPOT");
glutDisplayFunc (display);
glutMouseFunc(mouse);
glutMotionFunc(motion);
glutSpecialFunc(special);
glutMainLoop();
return 0;
}
運行這個程序我們會發現一個茶壺,我們可以通過鼠標和鍵盤的方向鍵來控制它的旋轉,而按下鼠標右鍵則可以讓這個茶壺自動旋轉,這裏還有幾個函數我們要注意一下
void glutWireTeapot(GLdouble size) 在當前的 OCS 座標中心畫一個以size爲大小的茶壺。
void glutSpecialFunc(void (*func)( int key, int x, int y)) 這個函數與glutKeyboardFunc的區別在於前者是用來響應鍵盤上的特殊按鍵,如方向鍵和控制鍵等。而後者則是用來響應鍵盤上的字符按鍵。
void glutTimerFunc(int delay, (void (*func)( int parameter),int parameter) 這個函數相當於win32
api 中的timer 定時器,也是在delay毫秒後放出一個定時器消息,而這裏的func 則爲這個消息的處理函數, patameter爲附加參數。這裏有一點要注意這個函數是一次性的,如果要重複使用可以在func中繼續調用glutTimerFunc,而且這個功能是可以疊加的,在opengl 內部將他們看成許多個不同的定時器,這也就是爲什麼我們在上面的例子中連續按下鼠標右鍵會加快旋轉的速度。