这是susu给我的一份关于glut的示例代码,里面涉及到的内容有:用glut来完成菜单管理,文本显示,显示列表,材质,光照,多窗口显示,鼠标事件处理,键盘事件处理,菜单事件处理,窗口创建,缩放,销毁,动画播放,定时器等功能,运行效果如图:

我分成几个部分来对代码进行分析:
1,命令行参数检查
{
int argp;
GLbooleanquit = GL_FALSE;
GLbooleanerror = GL_FALSE;
#define AAargv[argp]
argp = 1 ;
while (argp < argc)
{
if (match(AA, " -help " ))
{
commandLineHelp();
quit = GL_TRUE;
}
else if (match(AA, " -version " ))
{
printf(VERSIONLONG " /n " );
quit = GL_TRUE;
}
else if (match(AA, " -auto " ))
{ // 自动运行
demoMode = GL_TRUE;
}
else if (match(AA, " -scale " ))
{ // 放缩
argp ++ ;
scaleFactor = atof(argv[argp]); // 设置缩放因子
}
else
{ // 出错处理
fprintf(stderr, " Unknownarg:%s/n " ,AA);
error = GL_TRUE;
quit = GL_TRUE;
}
argp ++ ;
}
GLbooleanmatch( char * arg, char * t)
{
if (strstr(t,arg))
return GL_TRUE;
else
return GL_FALSE;
}
if (error)
{
commandLineHelp();
exit( 1 );
}
if (quit)
exit( 0 );
}
这里match函数考虑到-help可能被输入为-h等形式,因此用的是strstr而不是strcmp来进行字符串的匹配。
2,窗口的缩放
通过对窗口原点和大小的调整就可以实现窗口的缩放。
{ // 各个窗口的左上角坐标
{ 50 , 150 }, /* win0 */
{ 450 , 150 }, /* win1 */
{ 50 , 600 }, /* win2 */
{ 450 , 600 }, /* win3 */
{ 10 , 10 }, /* subwin4(relativetoparentwin0) */
{ 300 , 400 }, /* helpwin5 */
{ 850 , 150 }, /* cmapwin6 */
{ 850 , 600 }, /* cmapwin7 */
{ 250 , 450 } /* textwin8 */
};
int size[MAXWIN][ 2 ] =
{ // 各个窗口大小(宽度,高度)
{ 350 , 350 }, /* win0 */
{ 350 , 350 }, /* win1 */
{ 350 , 350 }, /* win2 */
{ 350 , 350 }, /* win3 */
{ 200 , 200 }, /* subwin4 */
{ 700 , 300 }, /* helpwin5 */
{ 350 , 350 }, /* cmapwin6 */
{ 350 , 350 }, /* cmapwin7 */
{ 800 , 450 } /* textwin8 */
};
void scaleWindows( float scale)
{ // 放缩初始窗口大小和位置
int i;
for (i = 0 ;i < MAXWIN;i ++ )
{
pos[i][ 0 ] = pos[i][ 0 ] * scale; // x坐标
pos[i][ 1 ] = pos[i][ 1 ] * scale; // y坐标
size[i][ 0 ] = size[i][ 0 ] * scale; // 宽度
size[i][ 1 ] = size[i][ 1 ] * scale; // 高度
}
}
3,设置显示模式、
Int型的数组modes用来记录各个模式位的值(0或者1),从而表明窗口是否支持这种模式。displayMode |= glutMode[i];通过这样的按位或运算最终获得窗口的显示模式。
modes[RGBA] = 1 ;
modes[DOUBLEBUFFER] = 1 ;
modes[DEPTH] = 1 ;
setInitDisplayMode()
void setInitDisplayMode( void )
{ // 设置初始显示模式
int i;
displayMode = 0 ;
for (i = 0 ;i < MODES;i ++ ){
if (modes[i]){
/* printf("Requesting%s/n",modeNames[i]); */
displayMode |= glutMode[i]; // 进行按位或运行,
}
}
glutInitDisplayMode(displayMode);
createMenu6();
if ( ! glutGet(GLUT_DISPLAY_MODE_POSSIBLE))
warning( " Thisdisplaymodenotsupported/n " );
}
4,菜单管理
menu1到menu8这8个int型变量用来保存创建的菜单项,并且menu2到menu8都作为menu1的子菜单加入到menu1中。


<!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>-->



























































































































5,创建窗口
本文中创建的窗口有4种类型,第1种是普通的RGB窗口,用来显示要绘制的图形,第2种是第1种窗口的子窗口(类似于“画中画”的效果),第3种是文本窗口和帮助窗口,第4种是颜色索引窗口。设置好窗口的显示模式,并根据保存的窗口大小和位置创建完窗口后,就可以对窗口进行OpenGL绘制的初始化工作,这是在gfxInit函数中完成的,最后就是为窗口加上各种事件处理函数。


<!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>-->


























































































































为每个窗口初始化OpenGL时,首先通过redefineShapes为窗口建立其显示列表,然后渲染其背景矩阵,接着进行投影变换和视图变换,为了简单起见,作者采用了默认的白色光源来进行材质和光源位置的设置,最后就是启用光照并设置窗口的背景颜色。


<!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>-->voidgfxInit(intindex)
{//为每个窗口初始化OpenGL
GLfloatgrey10[]=
{0.10,0.10,0.10,1.0};
GLfloatgrey20[]=
{0.2,0.2,0.2,1.0};
GLfloatblack[]=
{0.0,0.0,0.0,0.0};
//光源位置
GLfloatdiffuse0[]=
{1.0,0.0,0.0,1.0};
GLfloatdiffuse1[]=
{0.0,1.0,0.0,1.0};
GLfloatdiffuse2[]=
{1.0,1.0,0.0,1.0};
GLfloatdiffuse3[]=
{0.0,1.0,1.0,1.0};
GLfloatdiffuse4[]=
{1.0,0.0,1.0,1.0};
#defineXX3
#defineYY3
#defineZZ-2.5
//背景的包围矩阵
floatvertex[][3]=
{
{-XX,-YY,ZZ},
{+XX,-YY,ZZ},
{+XX,+YY,ZZ},
{-XX,+YY,ZZ}
};
/*warning:ThisfuncmixesRGBAandCMAPcallsinanugly
fashion*/
redefineShapes(currentShape);/*setupdisplaylists建立显示列表*/
glutSetWindow(winId[index]);//设置为当前窗口
/*hack-redefineShapes
changesglutwin*/
/*Shadedbackdropsquare(RGBorCMAP)*/
//渲染背景矩阵
glNewList(100,GL_COMPILE);
glPushAttrib(GL_LIGHTING);
glDisable(GL_LIGHTING);
glBegin(GL_POLYGON);
glColor4fv(black);
glIndexi(0);
glVertex3fv(vertex[0]);
glColor4fv(grey10);
glIndexi(3);
glVertex3fv(vertex[1]);
glColor4fv(grey20);
glIndexi(4);
glVertex3fv(vertex[2]);
glColor4fv(grey10);
glIndexi(7);
glVertex3fv(vertex[3]);
glEnd();
glPopAttrib();
glIndexi(9);
glEndList();
/*Setproj+view*/
//投影变换和视图变换
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(40.0,1.0,1.0,20.0);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
gluLookAt(0.0,0.0,5.0,0.0,0.0,0.0,0.0,1.0,0.);//gluLookAt前三个参数表示了观察点的位置,中间三个参数表示了观察目标的位置,最后三个参数代表从(0,0,0)到(x,y,z)的直线,它表示了观察者认为的“上”方向
glTranslatef(0.0,0.0,-1.0);//移入屏幕一个单位
if(index==6||index==7)//颜色索引模式
gotocolorindex;
/*Setbasicmaterial,lightingforRGBwindows*/
//材质和光源位置的设置(默认的白色光源)
if(index==0)
glMaterialfv(GL_FRONT,GL_DIFFUSE,diffuse0);
elseif(index==1)
glMaterialfv(GL_FRONT,GL_DIFFUSE,diffuse1);
elseif(index==2)
glMaterialfv(GL_FRONT,GL_DIFFUSE,diffuse2);
elseif(index==3)
glMaterialfv(GL_FRONT,GL_DIFFUSE,diffuse3);
elseif(index==4)
glMaterialfv(GL_FRONT,GL_DIFFUSE,diffuse4);
//启用光源
glEnable(GL_LIGHTING);
glEnable(GL_LIGHT0);
glEnable(GL_DEPTH_TEST);
if(index==4)
glClearColor(0.15,0.15,0.15,1);//设置子窗口的背景颜色
else
glClearColor(0.1,0.1,0.1,1.0);//其他窗口的背景颜色
return;
/*SetGLbasicsforCMAPwindows6,7*/
//颜色索引模式
colorindex:
glEnable(GL_DEPTH_TEST);
if(glutGet(GLUT_WINDOW_COLORMAP_SIZE)<16)
warning("Colormapsizetoosmallforcolorindexwindow");
/*Trytoreuseanexistingcolormap*/
if((index==6)&&(winId[7]!=0))
{
glutCopyColormap(winId[7]);
}elseif((index==7)&&(winId[6]!=0)){
glutCopyColormap(winId[6]);
}else{
glutSetColor(8,0.1,0.1,0.1);
glutSetColor(9,1.0,0.5,0.0);
glutSetColor(10,1.0,0.6,0.8);
}
glClearIndex(8);
glIndexi(index+3);
}
voidaddCallbacks(void)
{//为窗口增加回调函数
glutDisplayFunc(drawScene);
glutVisibilityFunc(visible);
glutReshapeFunc(reshapeFunc);
glutKeyboardFunc(keyFunc);
glutSpecialFunc(specialFunc);
glutMouseFunc(mouseFunc);
glutMotionFunc(motionFunc);
glutEntryFunc(entryFunc);
/*Callbacksforexoticinputdevices.Mustgetmydials&
buttonsback.*/
glutSpaceballMotionFunc(spaceballMotionCB);
glutSpaceballRotateFunc(spaceballRotateCB);
glutSpaceballButtonFunc(spaceballButtonCB);
glutButtonBoxFunc(buttonBoxCB);
glutDialsFunc(dialsCB);
glutTabletMotionFunc(tabletMotionCB);
glutTabletButtonFunc(tabletButtonCB);
}
6,动画效果
我在MFC中是通过设置一个定时器,并且在定时方法中修改旋转角度来刷新屏幕的,从而实现动画旋转的效果,在这里作者把这部分代码放到窗口的空闲事件处理函数中进行。每次执行时角度都进行了变换,并且通知窗口强制其重绘。
void idleFunc( void )
{
int i;
if ( ! leftDown && ! middleDown) // 旋转角度加1
angle += 1 ;
angle = angle % 360 ;
for (i = 0 ;i < MAXWIN;i ++ )
{
if (winId[i] && winVis[i] && ! winFreeze[i])
{
glutSetWindow(winId[i]);
glutPostRedisplay(); // 强制重画
}
}
}
7,自动演示
这里采用了一个小的技巧来实现多个窗口连续创建的自动演示功能。通过执行当前的动作后,为下一个应该接着发生的动作设置一个定时器,从而实现动作之间的接连发送效果。


<!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>-->voidautoDemo(intvalue)
{
staticintindex=0;
staticintcount=0;
staticintrestartValue=-2;
if(value==-999)
value=restartValue;
restartValue=value;
#defineAUTODELAY2(unsignedint)(AUTODELAY*0.66)
/*fprintf(stderr,"autoDemo:value%d/n",value);*/
if(!demoMode)
return;
if(menu_state==GLUT_MENU_IN_USE)
{
glutTimerFunc(AUTODELAY/2,autoDemo,value);
return;
}
switch(value)
{
/*Entrypoint;killoffexistingwindows.*/
case-2:
killAllWindows();
glutTimerFunc(AUTODELAY/2,autoDemo,1);
break;
/*Startmakingwindows*/
case-1:
makeWindow(0);
glutTimerFunc(AUTODELAY,autoDemo,0);/*skipcase0
firsttime*/
break;
/*Changeshape&backdrop*/
case0:
currentShape=(currentShape+1)%9;
redefineShapes(currentShape);
count+=1;
if(count%2)
backdrop=!backdrop;
glutTimerFunc(AUTODELAY,autoDemo,1);
break;
/*Keepmakingwindows*/
case1:
makeWindow(1);
glutTimerFunc(AUTODELAY,autoDemo,2);
break;
case2:
makeWindow(2);
glutTimerFunc(AUTODELAY,autoDemo,3);
break;
case3:
makeWindow(3);
glutTimerFunc(AUTODELAY,autoDemo,4);
break;
case4:
makeWindow(4);
glutTimerFunc(AUTODELAY,autoDemo,5);
break;
case5:
makeWindow(5);
glutTimerFunc(AUTODELAY*2,autoDemo,51);
break;
case51:
makeWindow(6);
glutTimerFunc(AUTODELAY*2,autoDemo,52);
break;
case52:
makeWindow(7);
glutTimerFunc(AUTODELAY*2,autoDemo,53);
break;
/*Killlast3windows,leave4up.*/
case53:
killWindow(7);
glutTimerFunc(AUTODELAY,autoDemo,54);
break;
case54:
killWindow(6);
glutTimerFunc(AUTODELAY,autoDemo,6);
break;
case6:
killWindow(5);
glutTimerFunc(AUTODELAY,autoDemo,7);
break;
case7:
killWindow(4);
glutTimerFunc(AUTODELAY,autoDemo,700);
break;
/*Changeshapeagain*/
case700:
currentShape=(currentShape+1)%9;
redefineShapes(currentShape);
glutTimerFunc(AUTODELAY,autoDemo,701);
break;
/*Cycle4mainwindowsthroughvariouswindowops.*/
case701:
positionWindow(index);
index=(index+1)%4;
glutTimerFunc(AUTODELAY2,autoDemo,index>0?701:702);
break;
case702:
reshapeWindow(index);
index=(index+1)%4;
glutTimerFunc(AUTODELAY2,autoDemo,index>0?702:703);
break;
case703:
iconifyWindow(index);
index=(index+1)%4;
glutTimerFunc(AUTODELAY2,autoDemo,index>0?703:704);
break;
case704:
showWindow(index);
index=(index+1)%4;
glutTimerFunc(AUTODELAY2,autoDemo,index>0?704:705);
break;
case705:
hideWindow(index);
index=(index+1)%4;
glutTimerFunc(AUTODELAY2,autoDemo,index>0?705:706);
break;
case706:
showWindow(index);
index=(index+1)%4;
glutTimerFunc(AUTODELAY2,autoDemo,index>0?706:707);
break;
case707:
pushWindow(index);
index=(index+1)%4;
glutTimerFunc(AUTODELAY2,autoDemo,index>0?707:708);
break;
case708:
popWindow(index);
index=(index+1)%4;
glutTimerFunc(AUTODELAY2,autoDemo,index>0?708:8);
break;
/*Killallwindows*/
case8:
killWindow(3);
glutTimerFunc(AUTODELAY,autoDemo,9);
break;
case9:
killWindow(2);
glutTimerFunc(AUTODELAY,autoDemo,10);
break;
case10:
killWindow(1);
glutTimerFunc(AUTODELAY,autoDemo,11);
break;
case11:
killWindow(0);
glutTimerFunc(AUTODELAY,autoDemo,-1);/*backtostart*/
break;
}
}
8,图形绘制代码部分
所有窗口都使用drawScene来绘制其图形,只是各个窗口调用的显示列表不同而已,这通过各个窗口的标识符来进行区别,并且通过调用trackBall(APPLY, 0, 0, 0, 0);来绘制鼠标左键控制的结果(旋转后的角度或者平移后的距离),如果窗口还有文本要显示,则调用showText来显示文本信息。


<!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>-->voiddrawScene(void)
{
intwinIndex;
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
winIndex=idToIndex(glutGetWindow());
/*printf("drawSceneforindex%d,id%d/n",winIndex,
glutGetWindow());*/
glPushMatrix();
glLineWidth(lineWidth);
if(backdrop)
glCallList(100);
/*Leftbuttonspinning*/
trackBall(APPLY,0,0,0,0);//鼠标左键控制结果的绘制
/*Applycontinuousspinning*/
glRotatef(angle,0,1,0);//绕y轴旋转
glCallList(winIndex+1);
glPopMatrix();
if(text[winIndex])
showText();//显示文本
glutSwapBuffers();
}
/*showText-RendersometextinthecurrentGLUTwindow*/
voidshowText(void)
{
glMatrixMode(GL_PROJECTION);
glPushMatrix();
glLoadIdentity();
gluOrtho2D(0,100,0,100);
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
glLoadIdentity();
glColor3f(1.0,1.0,1.0);
glIndexi(7);
glDisable(GL_DEPTH_TEST);
glDisable(GL_LIGHTING);
glLineWidth(lineWidth);
textString(1,1,"GLUT_BITMAP_8_BY_13",GLUT_BITMAP_8_BY_13);
textString(1,5,"GLUT_BITMAP_9_BY_15",GLUT_BITMAP_9_BY_15);
textString(1,10,"GLUT_BITMAP_TIMES_ROMAN_10",GLUT_BITMAP_TIMES_ROMAN_10);
textString(1,15,"GLUT_BITMAP_TIMES_ROMAN_24",GLUT_BITMAP_TIMES_ROMAN_24);
strokeString(1,25,"GLUT_STROKE_ROMAN",GLUT_STROKE_ROMAN);
strokeString(1,35,"GLUT_STROKE_MONO_ROMAN",GLUT_STROKE_MONO_ROMAN);
glEnable(GL_DEPTH_TEST);
glEnable(GL_LIGHTING);
glMatrixMode(GL_PROJECTION);
glPopMatrix();
glMatrixMode(GL_MODELVIEW);
glPopMatrix();
}
9.文本显示
这里有两种文本的显示方式,第一种采用位图字体来显示文本,第二种采用Stroke 字体来显示文本。
{ // 显示文本,x,y是起始坐标,msg:要显示的文本,font:显示的字体
glRasterPos2f(x,y); // 定位位图字体
while ( * msg)
{
glutBitmapCharacter(font, * msg);
msg ++ ;
}
}
/* strokeString-Strokefontstring */
void strokeString( int x, int y, char * msg, void * font)
{
glPushMatrix();
glTranslatef(x,y, 0 );
glScalef(. 04 ,. 04 ,. 04 );
while ( * msg)
{
glutStrokeCharacter(font, * msg);
msg ++ ;
}
glPopMatrix();
}
10,显示列表
显示列表由于是已经编译好的代码段,因此可以加快程序的速度。这里每种要绘制的图形(如球,茶壶等)都有实体和虚体两种模式可以选择。


<!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>-->voidredefineShapes(intshape)
{
inti;
//根据窗口号来绘制两种不同类型的图形
#defineC3/
switch(i)/
{/
case0:/
case3:/
C1;/
break;/
/
case1:/
case2:/
case4:/
case6:/
case7:/
C2;/
break;/
}/
currentShape=shape
for(i=0;i<MAXWIN;i++)
{//为每个要创建的窗口建立显示列表
if(winId[i])
{
glutSetWindow(winId[i]);
if(glIsList(i+1))
glDeleteLists(i+1,1);//若已经存在显示列表,就删除掉
glNewList(i+1,GL_COMPILE);//为当前窗口新建显示列表
switch(shape)
{
#undefC1
#defineC1glutSolidSphere(1.5,10,10)
#undefC2
#defineC2glutWireSphere(1.5,10,10)
case0:
C3;
break;
#undefC1
#defineC1glutSolidCube(2)
#undefC2
#defineC2glutWireCube(2)
case1:
C3;
break;
#undefC1
#defineC1glutSolidCone(1.5,1.75,10,10);
#undefC2
#defineC2glutWireCone(1.5,1.75,10,10);
case2:
C3;
break;
#undefC1
#defineC1glutSolidTorus(0.5,1.1,10,10)
#undefC2
#defineC2glutWireTorus(0.5,1.1,10,10)
case3:
C3;
break;
#undefC1
#defineC1glScalef(.8,.8,.8);glutSolidDodecahedron()
#undefC2
#defineC2glScalef(.8,.8,.8);glutWireDodecahedron()
case4:
C3;
break;
#undefC1
#defineC1glScalef(1.5,1.5,1.5);glutSolidOctahedron()
#undefC2
#defineC2glScalef(1.5,1.5,1.5);glutWireOctahedron()
case5:
C3;
break;
#undefC1
#defineC1glScalef(1.8,1.8,1.8);glutSolidTetrahedron()
#undefC2
#defineC2glScalef(1.8,1.8,1.8);glutWireTetrahedron()
case6:
C3;
break;
#undefC1
#defineC1glScalef(1.5,1.5,1.5);glutSolidIcosahedron()
#undefC2
#defineC2glScalef(1.5,1.5,1.5);glutWireIcosahedron()
case7:
C3;
break;
#undefC1
#defineC1glutSolidTeapot(1.5);
#undefC2
#defineC2glutWireTeapot(1.5);
case8:
C3;
break;
}
glEndList();
}
}
}
11,鼠标事件处理
这里鼠标有三种控制方式,1)左键进行旋转。2)中键进行xy平面的平移。3)左键+中键进行关于Z轴的平移(产生缩放的效果)。鼠标的事件模式这里有RESET,MOUSEBUTTON,APPLY, MOUSEMOTION四种,其中RESET是用来对清空以往的操作,让图形回到原点处。MOUSEBUTTON是鼠标按下激发的,用来记录下鼠标的位置,MOUSEMOTION是鼠标按下后并移动鼠标时,用来计算旋转的角度或者平移的距离,而最终这些变换后产生的效果的绘制是APPLY发生的,在这里进行了实际的旋转和平移动作。


<!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>-->voidtrackBall(intmode,intbutton,intstate,intx,inty)
{//鼠标控制
staticintstartMX=0,startMY=0;/*initialmousepos*/
staticintdeltaMX=0,deltaMY=0;/*initialmousepos*/
staticfloatsteadyXangle=0.0,steadyYangle=0.0;//绕x,y轴旋转的角度
staticfloatvarXangle=0.0,varYangle=0.0;
staticfloatsteadyX=0.0,steadyY=0.0,steadyZ=0.0;//;沿坐标轴缩放的比例
staticfloatvarX=0.0,varY=0.0,varZ=0.0;
switch(mode)
{
caseRESET://重置
steadyXangle=steadyYangle=steadyX=steadyY=steadyZ=0.0;
break;
caseMOUSEBUTTON:
if(button==GLUT_LEFT_BUTTON&&state==GLUT_DOWN&&!middleDown)
{//左键按下
STARTROTATE(x,y);//开始旋转,记录起始点坐标
leftDown=GL_TRUE;
}
elseif(button==GLUT_LEFT_BUTTON&&state==GLUT_DOWN&&
middleDown)
{//原来中键已按下且未放开,这时按下左键,则停止移动,开始缩放
STOPPAN(x,y);
STARTZOOM(x,y);
leftDown=GL_TRUE;
}
elseif(button==GLUT_MIDDLE_BUTTON&&state==GLUT_DOWN&&
!leftDown)
{//中键按下,开始移动
STARTPAN(x,y);
middleDown=GL_TRUE;
}
elseif(button==GLUT_MIDDLE_BUTTON&&state==GLUT_DOWN&&
leftDown)
{//原来左键已按下且未放开,这时按下中键,则停止旋转,开始缩放
STOPROTATE(x,y);
STARTZOOM(x,y);
middleDown=GL_TRUE;
}
elseif(state==GLUT_UP&&button==GLUT_LEFT_BUTTON&&!middleDown)
{//左键放开且中键未按下,停止旋转
STOPROTATE(x,y);
leftDown=GL_FALSE;
}
elseif(state==GLUT_UP&&button==GLUT_LEFT_BUTTON&&middleDown)
{//原来左中键已按下且未放开,这时放开左键,则停止缩放,开始旋转
STOPZOOM(x,y);
STARTROTATE(x,y);
leftDown=GL_FALSE;
}
elseif(state==GLUT_UP&&button==GLUT_MIDDLE_BUTTON&&!leftDown)
{
STOPPAN(x,y);
middleDown=GL_FALSE;
}
elseif(state==GLUT_UP&&button==GLUT_MIDDLE_BUTTON&&leftDown)
{
STOPZOOM(x,y);
STARTROTATE(x,y);
middleDown=GL_FALSE;
}
break;
caseAPPLY://结果的绘制
if(leftDown&&!middleDown)
{//旋转
glTranslatef(steadyX,steadyY,steadyZ);
glRotatef(varXangle,0,1,0);//绕y轴旋转
glRotatef(varYangle,1,0,0);//绕x轴旋转
}
/*Middlebuttonpan*/
elseif(middleDown&&!leftDown)
{//平移
glTranslatef(varX,varY,steadyZ);//在xy平面内平移
glRotatef(steadyXangle,0,1,0);
glRotatef(steadyYangle,1,0,0);
}
/*Left+middlezoom.*/
elseif(leftDown&&middleDown)
{//缩放(其实不能说缩放,只是让z轴的距离变化,镜头推近推远产生缩放的感觉)
glTranslatef(steadyX,steadyY,varZ);
glRotatef(steadyXangle,0,1,0);
glRotatef(steadyYangle,1,0,0);
}
/*Nothingdown.*/
else
{
glTranslatef(steadyX,steadyY,steadyZ);
glRotatef(steadyXangle,0,1,0);
glRotatef(steadyYangle,1,0,0);
}
break;
caseMOUSEMOTION:
deltaMX=x-startMX;//计算x的偏移量
deltaMY=startMY-y;//y的偏移量
if(leftDown&&!middleDown)
{//旋转
varXangle=fixAngle(steadyXangle+deltaMX);//计算旋转后对于y轴的角度
varYangle=fixAngle(steadyYangle+deltaMY);//计算旋转后对于x轴的角度
}
elseif(middleDown&&!leftDown)
{//移动
varX=steadyX+deltaMX/100.0;//平移后相对于x轴的距离
varY=steadyY+deltaMY/100.0;//平移后相对于y轴的距离
}
elseif(leftDown&&middleDown)
{//缩放
varZ=steadyZ-deltaMY/50.0;//相对于z轴的缩放比例
}
break;
}
}
最后,代码中还加入了对空间球,图形板,拨号按键盒的事件处理支持。