计算机图形学杨武影像科学与技术实验室东南大学计算机学院yangwu@seu.edu.cn2第三章之第二节回调3基本内容利用GLUT回调函数设计交互程序–鼠标–键盘–改变窗口形状在GLUT中定义菜单4鼠标回调函数glutMouseFunc(mymouse)voidmymouse(GLintbutton,GLintstate,GLintx,GLinty)–哪个键触发事件(GLUT_LEFT_BUTTON,GLUT_MIDDLE_BUTTON,GLUT_RIGHT_BUTTON)–按键状态(GLUT_UP,GLUT_DOWN)–光标在窗口中的位置坐标5定位在屏幕上的位置通常是以像素为单位的,原点在左上角在OpenGL中应用一个世界坐标系,其原点在左下角在这个坐标系中的y坐标需要从窗口高度中减去回调函数返回的y值:y:=h-y(0,0)hw6获取窗口尺寸为了完成y坐标的转换,需要知道窗口的尺寸–在程序执行过程中高度可能发生改变–需要利用一个全局变量跟踪其变化–新高度值返回给形状改变回调函数(见后)–也可以用查询函数glGetIntv和glGetFloatv获取,因为高度是状态的一部分7结束程序在以前的程序中没有办法通过OpenGL结束当前程序可以利用简单的鼠标回调函数做到这一点voidmouse(intbtn,intstate,intx,inty){if(btn==GLUT_RIGHT_BUTTON&&state==GLUT_DOWN)exit(0);}8鼠标位置的应用在要构造的例子中,每单击一次鼠标左按钮,就会在当前鼠标位置处画一个小方框在这个例子中并没有用到显示回调函数,但是由于GLUT要求必须有一个显示回调函数,因此要定义一个空函数mydisplay(){}9在指针处画方框voidmymouse(intbtn,intstate,intx,inty){if(btn==GLUT_RIGHT_BUTTON&&state==GLUT_DOWN)exit(0);if(btn==GLUT_LEFT_BUTTON&&state==GLUT_DOWN)drawSquare(x,y);}voiddrawSquare(intx,inty){y=w-y;/*invertyposition*/glColor3ub((char)rand()%256,(char)rand)%256,(char)rand()%256);/*arandomcolor*/glBegin(GL_POLYGON);glVertex2f(x+size,y+size);glVertex2f(x-size,y+size);glVertex2f(x-size,y-size);glVertex2f(x+size,y-size);glEnd();}10鼠标移动回调函数的应用通过利用移动回调函数可以在不释放鼠标按钮的情况下,连续画一系列方框–glutMotionFunc(drawSquare)应用被动移动回调函数,可以不用按鼠标按钮就可以连续画方框–glutPassiveMotionFunc(drawSquare)11键盘的应用glutKeyboardFunc(mykey)Voidmykey(unsignedcharkey,intx,inty)–返回键盘上被按下键的ASCII码和鼠标位置–注意在GLUT中并不把释放键做为一个事件voidmykey(){if(key==‘Q’|key==‘q’)exit(0);}12特殊按键GLUT在glut.h中定义了特殊按键:–功能键:GLUT_KEY_F1–向上方向键:GLUT_KEY_UP•if(key==‘GLUT_KEY_F1’……可以利用glutGetModifiers()探测是否按下了–GLUT_ACTIVE_SHIFT–GLUT_ACTIVE_CTRL–GLUT_ACTIVE_ALT–由此可以利用单钮或双钮鼠标模拟三钮鼠标13窗口形状的改变通过拖动窗口的角点可以改变窗口的形状和尺寸那么其中的显示内容该如何处理?–必须由应用程序重新绘制–有两种可能性•显示原来内容的一部分•通过强迫适应新窗口来显示所有内容–可能会改变了显示长宽比率14Reshapepossiblities初始图像改变后15形状改变的回调函数glutReshapeFunc(myreshape)voidmyreshape(intw,inth)–返回新窗口以像素为单位的宽度与高度–在回调函数执行后自动发送重新显示的事件–GLUT有一个缺省的形状改变的回调函数,但用户可能需要定义自己的行为这个回调函数是放置照相机函数的恰当地方,因为当窗口第一次被打开时就会调用这个函数16例子在下面的例子中,保持视口和世界窗口的长宽比率不变voidmyReshape(intw,inth){glViewport(0,0,w,h);glMatrixMode(GL_PROJECTION);glLoadIdentity();if(w=h)gluOrtho2D(-2.0,2.0,-2.0*(GLfloat)h/(GLfloat)w,2.0*(GLfloat)h/(GLfloat)w);elsegluOrtho2D(-2.0*(GLfloat)w/(GLfloat)h,2.0*(GLfloat)w/(GLfloat)h,-2.0,2.0);glMatrixMode(GL_MODELVIEW);}17窗口资源许多窗口系统提供了一个工具包或者一组库函数用来建立用户界面,界面中用到了一些特殊类型的窗口,称为资源构件(widget)构件集合中包含下述工具:–菜单–滑动条–对话框–输入文本框但上述构件通常都是与平台相关的GLUT只提供了包含菜单在内的很少几个构件18菜单GLUT支持弹出式菜单–可以有子菜单创建弹出式菜单的三个步骤–定义菜单内各条目–定义每个菜单项的行为•如果条目被选择执行的操作–把菜单连接到鼠标按钮上19定义一个简单菜单在main()中menu_id=glutCreateMenu(mymenu);glutAddmenuEntry(“clearScreen”,1);gluAddMenuEntry(“exit”,2);glutAttachMenu(GLUT_RIGHT_BUTTON);当按下右按键时,就会出现的条目标识符clearscreenexit20菜单的行为菜单回调函数注意在创建菜单时每项都有一个标识符添加子菜单glutAddSubMenu(char*submenu_name,submenuid)voidmymenu(intid){if(id==1)glClear();if(id==2)exit(0);}21GLUT中的其它函数动态窗口–在执行期间创建或关闭窗口子窗口多重窗口在执行期间改变回调函数计时器字体–glutBitmapCharacter–glutStrokeCharacter