代码分析

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

200782201.jpg

我分成几个部分来对代码进行分析:

1,命令行参数检查

<!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--> void checkArgs( int argc, char * argv[])
{
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,窗口的缩放

通过对窗口原点和大小的调整就可以实现窗口的缩放。

<!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--> int pos[MAXWIN][ 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];通过这样的按位或运算最终获得窗口的显示模式。

<!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--> int modes[MODES] = { 0 };
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,菜单管理

menu1menu88int型变量用来保存创建的菜单项,并且menu2menu8都作为menu1的子菜单加入到menu1中。

ContractedBlock.gif ExpandedBlockStart.gif 创建菜单
<!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>-->None.gif
None.gif
voidmakeMenus(void)
ExpandedBlockStart.gifContractedBlock.gif
dot.gif{//创建弹出菜单
InBlock.gif

ExpandedSubBlockStart.gifContractedSubBlock.gif
/**//*Generalcontrol/debug*/
InBlock.gif
InBlock.gifmenu2
=glutCreateMenu(menuFunc);
InBlock.gifglutAddMenuEntry(
"toggleautodemomode(a)",312);
InBlock.gifglutAddMenuEntry(
"togglefreezinginmenus",300);
InBlock.gifglutAddMenuEntry(
"toggletextperwindow(t)",301);
InBlock.gifglutAddMenuEntry(
"toggleglobaltimer",302);
InBlock.gifglutAddMenuEntry(
"toggleglobalanimation",303);
InBlock.gifglutAddMenuEntry(
"toggleperwindowanimation",304);
InBlock.gifglutAddMenuEntry(
"toggledebugprints(D)",305);
InBlock.gifglutAddMenuEntry(
"toggleshadedbackdrop",307);
InBlock.gifglutAddMenuEntry(
"togglepassivemotioncallback",308);
InBlock.gifglutAddMenuEntry(
"increaselinewidth(l)",310);
InBlock.gifglutAddMenuEntry(
"decreaselinewidth(L)",311);
InBlock.gif
ExpandedSubBlockStart.gifContractedSubBlock.gif
/**//*Shapes*/
InBlock.gif
InBlock.gifmenu3
=glutCreateMenu(menuFunc);
InBlock.gifglutAddMenuEntry(
"sphere",200);
InBlock.gifglutAddMenuEntry(
"cube",201);
InBlock.gifglutAddMenuEntry(
"cone",202);
InBlock.gifglutAddMenuEntry(
"torus",203);
InBlock.gifglutAddMenuEntry(
"dodecahedron",204);
InBlock.gifglutAddMenuEntry(
"octahedron",205);
InBlock.gifglutAddMenuEntry(
"tetrahedron",206);
InBlock.gifglutAddMenuEntry(
"icosahedron",207);
InBlock.gifglutAddMenuEntry(
"teapot",208);
InBlock.gif
ExpandedSubBlockStart.gifContractedSubBlock.gif
/**//*Open/closewindows*/
InBlock.gif
InBlock.gifmenu4
=glutCreateMenu(menuFunc);
InBlock.gifglutAddMenuEntry(
"openallwindows",450);
InBlock.gifglutAddMenuEntry(
"closeallwindows",451);
InBlock.gifglutAddMenuEntry(
"",9999);
InBlock.gifglutAddMenuEntry(
"createwin0",400);
InBlock.gifglutAddMenuEntry(
"createwin1",401);
InBlock.gifglutAddMenuEntry(
"createwin2",402);
InBlock.gifglutAddMenuEntry(
"createwin3",403);
InBlock.gifglutAddMenuEntry(
"createsubwindow",404);
InBlock.gifglutAddMenuEntry(
"createcolorindexwin6",406);
InBlock.gifglutAddMenuEntry(
"createcolorindexwin7",407);
InBlock.gifglutAddMenuEntry(
"",9999);
InBlock.gifglutAddMenuEntry(
"destroywin0",410);
InBlock.gifglutAddMenuEntry(
"destroywin1",411);
InBlock.gifglutAddMenuEntry(
"destroywin2",412);
InBlock.gifglutAddMenuEntry(
"destroywin3",413);
InBlock.gifglutAddMenuEntry(
"destroysubwindow",414);
InBlock.gifglutAddMenuEntry(
"destroycolorindexwin6",416);
InBlock.gifglutAddMenuEntry(
"destroycolorindexwin7",417);
InBlock.gif
ExpandedSubBlockStart.gifContractedSubBlock.gif
/**//*Windowmanagerstuff*/
InBlock.gif
InBlock.gifmenu5
=glutCreateMenu(menuFunc);
InBlock.gifglutAddMenuEntry(
"movecurrentwin",430);
InBlock.gifglutAddMenuEntry(
"resizecurrentwin",431);
InBlock.gifglutAddMenuEntry(
"iconifycurrentwin",432);
InBlock.gifglutAddMenuEntry(
"showcurrentwin",433);
InBlock.gifglutAddMenuEntry(
"hidecurrentwin",434);
InBlock.gifglutAddMenuEntry(
"pushcurrentwin",435);
InBlock.gifglutAddMenuEntry(
"popcurrentwin",436);
InBlock.gifglutAddMenuEntry(
"",9999);
InBlock.gifglutAddMenuEntry(
"movewin1",420);
InBlock.gifglutAddMenuEntry(
"resizewin1",421);
InBlock.gifglutAddMenuEntry(
"iconifywin1",422);
InBlock.gifglutAddMenuEntry(
"showwin1",423);
InBlock.gifglutAddMenuEntry(
"hidewin1",424);
InBlock.gifglutAddMenuEntry(
"pushwin1",425);
InBlock.gifglutAddMenuEntry(
"popwin1",426);
InBlock.gif
ExpandedSubBlockStart.gifContractedSubBlock.gif
/**//*Gfxmodes*/
InBlock.gif
ExpandedSubBlockStart.gifContractedSubBlock.gifcreateMenu6();
/**//*builddynamically*/
InBlock.gif
ExpandedSubBlockStart.gifContractedSubBlock.gif
/**//*Textyreports*/
InBlock.gif
InBlock.gifmenu7
=glutCreateMenu(menuFunc);
InBlock.gifglutAddMenuEntry(
"reportcurrentwinmodes",700);
InBlock.gifglutAddMenuEntry(
"reportcurrentdevicedata",701);
InBlock.gifglutAddMenuEntry(
"checkOpenGLextensions",702);
InBlock.gifglutAddMenuEntry(
"dumpinternaldata(d)",703);
InBlock.gif
ExpandedSubBlockStart.gifContractedSubBlock.gif
/**//*Playwithmenus*/
InBlock.gif
InBlock.gifmenu8
=glutCreateMenu(menuFunc);
InBlock.gifglutAddMenuEntry(
"togglemenusonleftbutton",805);
InBlock.gifglutAddMenuEntry(
"togglemenusonmiddlebutton",806);
InBlock.gifglutAddMenuEntry(
"togglemenusonrightbutton",807);
InBlock.gifglutAddMenuEntry(
"---------------------------",9999);
InBlock.gifglutAddMenuEntry(
"addplainitems",800);
InBlock.gifglutAddMenuEntry(
"addsubmenuitems",801);
InBlock.gifglutAddMenuEntry(
"changenewentriestoplainitems",802);
InBlock.gifglutAddMenuEntry(
"changenewentriestosubmenus",803);
InBlock.gifglutAddMenuEntry(
"removeallnewitems",804);
InBlock.gifglutAddMenuEntry(
"---------------------------",9999);
InBlock.gif
ExpandedSubBlockStart.gifContractedSubBlock.gif
/**//*Mainmenu*/
InBlock.gif
InBlock.gifmenu1
=glutCreateMenu(menuFunc);
InBlock.gifglutAddSubMenu(
"control",menu2);
InBlock.gifglutAddSubMenu(
"shapes",menu3);
InBlock.gifglutAddSubMenu(
"windows",menu4);
InBlock.gifglutAddSubMenu(
"windowops",menu5);
InBlock.gifglutAddSubMenu(
"gfxmodes",menu6);
InBlock.gifglutAddSubMenu(
"reports",menu7);
InBlock.gifglutAddSubMenu(
"menus",menu8);
InBlock.gifglutAddMenuEntry(
"help(h)",101);
InBlock.gifglutAddMenuEntry(
"quit(esc)",100);
ExpandedBlockEnd.gif}

5,创建窗口

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

ContractedBlock.gif ExpandedBlockStart.gif 创建窗口
<!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>-->None.gifvoidmakeWindow(intindex)
ExpandedBlockStart.gifContractedBlock.gif
dot.gif{//建立窗口
InBlock.gif
charstr[99];
InBlock.gif
InBlock.gif
if(winId[index]!=0)
ExpandedSubBlockStart.gifContractedSubBlock.gif
dot.gif{//已经存在的窗口
ExpandedSubBlockStart.gifContractedSubBlock.gif
/**//*warning("Attempttocreatewindowwhichisalready
ExpandedSubBlockEnd.gifcreated");
*/

InBlock.gif
return;
ExpandedSubBlockEnd.gif}

InBlock.gif
switch(index)
ExpandedSubBlockStart.gifContractedSubBlock.gif
dot.gif{
InBlock.gif
//普通的RGB窗口
ExpandedSubBlockStart.gifContractedSubBlock.gif
case0:/**//*ordinaryRGBwindows*/
InBlock.gif
case1:
InBlock.gif
case2:
InBlock.gif
case3:
InBlock.gif
InBlock.gifsetInitDisplayMode();
InBlock.gifglutInitWindowPosition(pos[index][
0],pos[index][1]);//窗口左上角位置
InBlock.gif
glutInitWindowSize(size[index][0],size[index][1]);//窗口大小
InBlock.gif
winId[index]=glutCreateWindow("");//保存窗口标识符
InBlock.gif
PR("Window%did=%d/n",index,winId[index]);
InBlock.gifgfxInit(index);
//初始化openGL
InBlock.gif

InBlock.gifaddCallbacks();
InBlock.gif
InBlock.gifsprintf(str,
"window%d(RGB)",index);
InBlock.gifglutSetWindowTitle(str);
InBlock.gifsprintf(str,
"icon%d",index);
InBlock.gifglutSetIconTitle(str);
InBlock.gifglutSetMenu(menu1);
InBlock.gifglutAttachMenu(GLUT_RIGHT_BUTTON);
InBlock.gif
break;
InBlock.gif
ExpandedSubBlockStart.gifContractedSubBlock.gif
case4:/**//*subwindow子窗口*/
InBlock.gif
InBlock.gifsetInitDisplayMode();
InBlock.gifwinId[index]
=glutCreateSubWindow(winId[0],pos[index][0],pos[index]
InBlock.gif[
1],size[index][0],size[index][1]);
InBlock.gifPR(
"Window%did=%d/n",index,winId[index]);
InBlock.gifgfxInit(index);
InBlock.gifglutDisplayFunc(drawScene);
InBlock.gifglutVisibilityFunc(visible);
InBlock.gifglutReshapeFunc(reshapeFunc);
InBlock.gif
InBlock.gif
break;
InBlock.gif
ExpandedSubBlockStart.gifContractedSubBlock.gif
case5:/**//*helpwindow帮助窗口*/
ExpandedSubBlockStart.gifContractedSubBlock.gif
case8:/**//*textwindow文本窗口*/
InBlock.gifglutInitDisplayMode(GLUT_DOUBLE
|GLUT_RGB|GLUT_DEPTH);
InBlock.gifglutInitWindowPosition(pos[index][
0],pos[index][1]);
InBlock.gifglutInitWindowSize(size[index][
0],size[index][1]);
InBlock.gifwinId[index]
=glutCreateWindow("");
InBlock.gifPR(
"Window%did=%d/n",index,winId[index]);
InBlock.gif
ExpandedSubBlockStart.gifContractedSubBlock.gif
/**//*addCallbacks();*/
InBlock.gifglutKeyboardFunc(keyFunc);
InBlock.gifglutSpecialFunc(specialFunc);
InBlock.gif
InBlock.gifglClearColor(
0.15,0.15,0.15,1.0);
InBlock.gifglColor3f(
1,1,1);
InBlock.gifglMatrixMode(GL_PROJECTION);
InBlock.gifglLoadIdentity();
InBlock.gifgluOrtho2D(
0,300,0,100);
InBlock.gifglMatrixMode(GL_MODELVIEW);
InBlock.gifglLoadIdentity();
InBlock.gif
ExpandedSubBlockStart.gifContractedSubBlock.gif
if(index==5)dot.gif{
InBlock.gifglutDisplayFunc(updateHelp);
InBlock.gifglutSetWindowTitle(
"help(RGB)win5");
InBlock.gifglutSetIconTitle(
"help");
ExpandedSubBlockStart.gifContractedSubBlock.gif}
elsedot.gif{
InBlock.gifglutDisplayFunc(updateText);
InBlock.gifglutSetWindowTitle(
"text(RGB)win8");
InBlock.gifglutSetIconTitle(
"text");
ExpandedSubBlockEnd.gif}

InBlock.gifglutSetMenu(menu1);
InBlock.gifglutAttachMenu(GLUT_RIGHT_BUTTON);
InBlock.gif
break;
InBlock.gif
ExpandedSubBlockStart.gifContractedSubBlock.gif
case6:/**//*colorindexwindow颜色索引窗口*/
ExpandedSubBlockStart.gifContractedSubBlock.gif
case7:/**//*colorindexwindow*/
InBlock.gif
InBlock.gifglutInitDisplayMode(GLUT_DOUBLE
|GLUT_INDEX|GLUT_DEPTH);
InBlock.gifglutInitWindowPosition(pos[index][
0],pos[index][1]);
InBlock.gifglutInitWindowSize(size[index][
0],size[index][1]);
InBlock.gifwinId[index]
=glutCreateWindow("");
InBlock.gifPR(
"Window%did=%d/n",index,winId[index]);
InBlock.gif
InBlock.gifgfxInit(index);
InBlock.gif
InBlock.gifaddCallbacks();
InBlock.gif
InBlock.gifsprintf(str,
"window%d(colorindex)",index);
InBlock.gifglutSetWindowTitle(str);
InBlock.gifsprintf(str,
"icon%d",index);
InBlock.gifglutSetIconTitle(str);
InBlock.gifglutSetMenu(menu1);
InBlock.gifglutAttachMenu(GLUT_RIGHT_BUTTON);
InBlock.gif
break;
InBlock.gif
ExpandedSubBlockEnd.gif}

ExpandedBlockEnd.gif}

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

ContractedBlock.gif ExpandedBlockStart.gif OpenGL初始化
<!--<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中是通过设置一个定时器,并且在定时方法中修改旋转角度来刷新屏幕的,从而实现动画旋转的效果,在这里作者把这部分代码放到窗口的空闲事件处理函数中进行。每次执行时角度都进行了变换,并且通知窗口强制其重绘。

<!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--> /* idleFunc-GLUTidlefunccallback-animateswindows */
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,自动演示

这里采用了一个小的技巧来实现多个窗口连续创建的自动演示功能。通过执行当前的动作后,为下一个应该接着发生的动作设置一个定时器,从而实现动作之间的接连发送效果。

ContractedBlock.gif ExpandedBlockStart.gif 旋转动画
<!--<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来显示文本信息。

ContractedBlock.gif ExpandedBlockStart.gif 图形绘制代码
<!--<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 字体来显示文本。

<!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--> void textString( int x, int y, char * msg, void * font)
{
// 显示文本,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,显示列表

显示列表由于是已经编译好的代码段,因此可以加快程序的速度。这里每种要绘制的图形(如球,茶壶等)都有实体和虚体两种模式可以选择。

ContractedBlock.gif ExpandedBlockStart.gif 显示列表
<!--<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轴的平移(产生缩放的效果)。鼠标的事件模式这里有RESETMOUSEBUTTONAPPLY MOUSEMOTION四种,其中RESET是用来对清空以往的操作,让图形回到原点处。MOUSEBUTTON是鼠标按下激发的,用来记录下鼠标的位置,MOUSEMOTION是鼠标按下后并移动鼠标时,用来计算旋转的角度或者平移的距离,而最终这些变换后产生的效果的绘制是APPLY发生的,在这里进行了实际的旋转和平移动作。

ContractedBlock.gif ExpandedBlockStart.gif 鼠标控制
<!--<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;
}

}

最后,代码中还加入了对空间球,图形板,拨号按键盒的事件处理支持。




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值