检测鼠标单击
要想在OpenGL中处理鼠标事件非常的方便,GLUT已经为我们的注册好了函数,只要我们提供一个方法。使用函数glutMouseFunc,就可以帮我们注册我们的函数,这样当发生鼠标事件时就会自动调用我们的方法。
函数的原型是:
void glutMouseFunc(void(*func)(int button,int state,int x,int y));
参数:
func:处理鼠标click事件的函数的函数名。
从上面可以看到,处理鼠标单击事件的函数,一定有4个参数。第一个参数表明哪个鼠标键被按下或松开,这个变量可以是下面的三个值中的一个:
GLUT_LEFT_BUTTON
GLUT_MIDDLE_BUTTON
GLUT_RIGHT_BUTTON
// 下面两个是重构的OpenGL库函数中带的值,表示滚轮上下滚动的状态
GLUT_WHEEL_UP
GLUT_WHEEL_DOWN
第二个参数表明,函数被调用发生时,鼠标键的状态,也就是被按下,或松开,可能取值如下:
GLUT_DOWN
GLUT_UP
当函数被调用时,state的值是GLUT _DOWN。那么程序可能会假定将会有个GLUT _UP事件,甚至鼠标移动到窗口外面,也如此。然而,如果程序调用glutMouseFunc传递NULL作为参数,那么GLUT将不会改变鼠标的状态。
剩下的两个参数(x,y)提供了鼠标当前的窗口坐标(以左上角为原点)。
检测动作
GLUT提供鼠标动作检测能力。有两种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
应用
现在想实现的功能就是使用鼠标拖动,来转动场景中的物体,当鼠标左键按下,并且上下左右滑动时,场景中的模型相应的会随之上下左右旋转,当鼠标右键按下,并且上下左右滑动时,场景中的模型相应的会随之在屏幕中进行平移。
首先,定义几个全局变量:
bool mouseLeftDown;
bool mouseRightDown;
bool mouseMiddleDown;
float mouseX, mouseY;
float cameraDistanceX;
float cameraDistanceY;
float cameraAngleX;
float cameraAngleY;
float times=1;
其中,mouseLeftDown和 mouseRightDown变量标志鼠标左右键按下与否,mouseX和mouseY变量标志鼠标滑动时,前一刻的鼠标所在位置。
cameraDistanceX和cameraDistanceY变量根据鼠标右键按下并滑动操作来控制模型物体的平移。cameraAngleX和cameraAngleY变量根据鼠标左键按下并滑动来控制场景中物体的旋转。
times变量表示缩放倍数,默认是原样缩放,为1倍。
void mouseCB(int button, int state, int x, int y)
{
mouseX = x;
mouseY = y;
times = 1;
if(button == GLUT_LEFT_BUTTON)
{
if(state == GLUT_DOWN)
{
mouseLeftDown = true;
}
else if(state == GLUT_UP)
mouseLeftDown = false;
}
else if(button == GLUT_RIGHT_BUTTON)
{
if(state == GLUT_DOWN)
{
mouseRightDown = true;
}
else if(state == GLUT_UP)
mouseRightDown = false;
}
/*
* 鼠标滚轮控制图形缩放
*/
else if (state == GLUT_UP && button == GLUT_WHEEL_UP)
{
times = 0.008f+1;
glutPostRedisplay();
}
else if (state == GLUT_UP && button == GLUT_WHEEL_DOWN)
{
times = -0.008f+1;
glutPostRedisplay();
}
}
void mouseMotionCB(int x, int y)
{
cameraAngleX = cameraAngleY = 0;
cameraDistanceX = cameraDistanceY = 0;
if (mouseLeftDown)
{
cameraAngleY += (x - mouseX) * 0.1f;
cameraAngleX += (y - mouseY) * 0.1f;
mouseX = x;
mouseY = y;
}
if (mouseRightDown)
{
cameraDistanceX = (x - mouseX) * 0.002f;
cameraDistanceY = -(y - mouseY) * 0.002f;
mouseY = y;
mouseX = x;
}
glutPostRedisplay();
}
最后,在主函数中,调用相应的函数注册即可:
glutMouseFunc(mouseCB);
glutMotionFunc(mouseMotionCB);
在场景中物体绘制之前,这样就可以:
glScalef(times, times, times);//缩放
glTranslatef(cameraDistanceX, cameraDistanceY, 0);
glRotatef(cameraAngleX, 1, 0, 0);
glRotatef(cameraAngleY, 0, 1, 0);
备注
由于默认的OpenGL库中,不含接收鼠标滚轮输入的库函数,故在本文中的所有与滚轮控制缩放相关的功能实现,需要配置重构的OpenGL库。具体资源及使用注意我已经打包好了,下载地址是:
下载:OpenGL库函数拓展
完成效果的视频演示:
视频演示
源码参见:
源码传送门