轉自:http://blog.csdn.net/xie_zi/article/details/1925778
在前幾節,我們看了怎麼使用GLUT的keyboard函數,來增加一個OpenGL程序的交互性。現在,是時候研究下鼠標了。GLUT的鼠標接口提供一些列的選項來增加鼠標的交互性。也就是檢測鼠標單擊,和鼠標移動。
檢測鼠標Clicks
和鍵盤處理一樣,GLUT爲你的註冊函數(也就是處理鼠標clicks事件的函數)提供了一個方法。函數glutMouseFunc,這個函數一般在程序初始化階段被調用。函數原型如下:
void glutMouseFunc(void(*func)(int button,int state,int x,int y));
參數:
func:處理鼠標click事件的函數的函數名。
從上面可以看到到,處理鼠標click事件的函數,一定有4個參數。第一個參數表明哪個鼠標鍵被按下或鬆開,這個變量可以是下面的三個值中的一個:
GLUT_LEFT_BUTTON
GLUT_MIDDLE_BUTTON
GLUT_RIGHT_BUTTON
第二個參數表明,函數被調用發生時,鼠標的狀態,也就是是被按下,或鬆開,可能取值如下:
GLUT_DOWN
GLUT_UP
當函數被調用時,state的值是GLUT_DOWN,那麼程序可能會假定將會有個GLUT_UP事件,甚至鼠標移動到窗口外面,也如此。然而,如果程序調用glutMouseFunc傳遞NULL作爲參數,那麼GLUT將不會改變鼠標的狀態。
剩下的兩個參數(x,y)提供了鼠標當前的窗口座標(以左上角爲原點)。
檢測動作(motion)
GLUT提供鼠標motion檢測能力。有兩種GLUT處理的motion:active motion和passive motion。Active motion是指鼠標移動並且有一個鼠標鍵被按下。Passive motion是指當鼠標移動時,並有沒鼠標鍵按下。如果一個程序正在追蹤鼠標,那麼鼠標移動期間,沒一幀將產生一個結果。
和以前一樣,你必須註冊將處理鼠標事件的函數(定義函數)。GLUT讓我們可以指定兩個不同的函數,一個追蹤passive motion,另一個追蹤active motion
它們的函數原型,如下:
void glutMotionFunc(void(*func)(int x,int y));
void glutPassiveMotionFunc(void (*func)(int x,int y));
參數:
Func:處理各自類型motion的函數名。
處理motion的參數函數的參數(x,y)是鼠標在窗口的座標。以左上角爲原點。
檢測鼠標進入或離開窗口
GLUT還能檢測鼠標鼠標離開,進入窗口區域。一個回調函數可以被定義去處理這兩個事件。GLUT裏,調用這個函數的是glutEntryFunc,函數原型如下:
void glutEntryFunc(void(*func)(int state));
參數:
Func:處理這些事件的函數名。
上面函數的參數中,state有兩個值:
GLUT_LEFT
GLUT_ENTERED
表明,是離開,還是進入窗口。
把它們放一起
首先我們要做的是在GLUT裏定義哪些函數將負責處理鼠標事件。因此我們將重寫我們的main函數,讓它包含所有必須的回調註冊函數。我們將在程序裏描述其他一些教程裏沒說清楚的地方。
void main(int argc, char **argv) {
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DEPTH | GLUT_DOUBLE | GLUT_RGBA);
glutInitWindowPosition(100,100);
glutInitWindowSize(320,320);
glutCreateWindow("SnowMen");
glutDisplayFunc(renderScene);
glutIdleFunc(renderScene);
glutReshapeFunc(changeSize);
//adding here the mouse processing callbacks
glutMouseFunc(processMouse);
glutMotionFunc(processMouseActiveMotion);
glutPassiveMotionFunc(processMousePassiveMotion);
glutEntryFunc(processMouseEntry);
glutMainLoop();
}
OK,現在做點有趣的。我們將定義那些將做一些不可思議事件的回調函數。當一個鼠標鍵和alt鍵都被按下,我們將改變三角形的顏色。鼠標左鍵使三角形變成紅色,中間的將三角形變成綠色,鼠標右鍵將三角形變成藍色。函數如下:
void processMouse(int button, int state, int x, int y) {
specialKey = glutGetModifiers();
//
當鼠標鍵和alt鍵都被按下
if ((state == GLUT_DOWN) &&
(specialKey == GLUT_ACTIVE_ALT)) {
// set the color to pure red for the left button
if (button == GLUT_LEFT_BUTTON) {
red = 1.0; green = 0.0; blue = 0.0;
}
// set the color to pure green for the middle button
else if (button == GLUT_MIDDLE_BUTTON) {
red = 0.0; green = 1.0; blue = 0.0;
}
// set the color to pure blue for the right button
else {
red = 0.0; green = 0.0; blue = 1.0;
}
}
}
接下來有一個精細的顏色拾取方法。當一個鼠標鍵被按下,但alt鍵被被按下。我們把blue設爲0.0,並且讓red和green分量的值取決於鼠標在窗口中的位置。。函數如下:
void processMouseActiveMotion(int x, int y) {
// the ALT key was used in the previous function
if (specialKey != GLUT_ACTIVE_ALT) {
// setting red to be relative to the mouse
// position inside the window
if (x < 0)
red = 0.0;
else if (x > width)
red = 1.0;
else
red = ((float) x)/height;
// setting green to be relative to the mouse
// position inside the window
if (y < 0)
green = 0.0;
else if (y > width)
green = 1.0;
else
green = ((float) y)/height;
// removing the blue component.
blue = 0.0;
}
}
下面給passive motion添加一些動作。當shift鍵被按下,鼠標將在x軸上有一個旋轉。我們不得不修改renderScene函數。函數如下:
float angleX = 0.0;
...
void renderScene(void) {
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glPushMatrix();
glRotatef(angle,0.0,1.0,0.0);
// This is the line we added for the
// rotation on the X axis;
glRotatef(angleX,1.0,0.0,0.0);
glColor3f(red,green,blue);
glBegin(GL_TRIANGLES);
glVertex3f(-0.5,-0.5,0.0);
glVertex3f(0.5,0.0,0.0);
glVertex3f(0.0,0.5,0.0);
glEnd();
glPopMatrix();
angle++;
glutSwapBuffers();
}
現在我們的有個函數處理passive motion事件。函數將改變angleX的值。
void processMousePassiveMotion(int x, int y) {
// User must press the SHIFT key to change the
// rotation in the X axis
if (specialKey != GLUT_ACTIVE_SHIFT) {
// setting the angle to be relative to the mouse
// position inside the window
if (x < 0)
angleX = 0.0;
else if (x > width)
angleX = 180.0;
else
angleX = 180.0 * ((float) x)/height;
}
}
最後鼠標離開窗口將使動畫停止,爲了做到這,我們也需要改變函數renderScene。
// initially define the increase of the angle by 1.0;
float deltaAngle = 1.0;
...
void renderScene(void) {
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glPushMatrix();
glRotatef(angle,0.0,1.0,0.0);
glRotatef(angleX,1.0,0.0,0.0);
glColor3f(red,green,blue);
glBegin(GL_TRIANGLES);
glVertex3f(-0.5,-0.5,0.0);
glVertex3f(0.5,0.0,0.0);
glVertex3f(0.0,0.5,0.0);
glEnd();
glPopMatrix();
// this is the new line
// previously it was: angle++;
angle+=deltaAngle;
glutSwapBuffers();
}
processMouseEntry是最後一個函數。注意,這個在微軟操作系統下可能工作的不是很好。
void processMouseEntry(int state) {
if (state == GLUT_LEFT)
deltaAngle = 0.0;
else
deltaAngle = 1.0;
}