`
dato0123
  • 浏览: 915076 次
文章分类
社区版块
存档分类
最新评论

代码分析

 
阅读更多

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

200782201.jpg

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

1,命令行参数检查

<!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>-->voidcheckArgs(intargc,char*argv[])
{
intargp;
GLbooleanquit
=GL_FALSE;
GLbooleanerror
=GL_FALSE;
#defineAAargv[argp]
argp
=1;
while(argp<argc)
{
if(match(AA,"-help"))
{
commandLineHelp();
quit
=GL_TRUE;
}
elseif(match(AA,"-version"))
{
printf(VERSIONLONG
"/n");
quit
=GL_TRUE;
}
elseif(match(AA,"-auto"))
{
//自动运行
demoMode=GL_TRUE;
}
elseif(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))
returnGL_TRUE;
else
returnGL_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>-->intpos[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*/
};
intsize[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*/
};
voidscaleWindows(floatscale)
{
//放缩初始窗口大小和位置
inti;
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>-->intmodes[MODES]={0};
modes[RGBA]
=1;
modes[DOUBLEBUFFER]
=1;
modes[DEPTH]
=1;
setInitDisplayMode()
voidsetInitDisplayMode(void)
{
//设置初始显示模式
inti;
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中。

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

/**//*Generalcontrol/debug*/

menu2
=glutCreateMenu(menuFunc);
glutAddMenuEntry(
"toggleautodemomode(a)",312);
glutAddMenuEntry(
"togglefreezinginmenus",300);
glutAddMenuEntry(
"toggletextperwindow(t)",301);
glutAddMenuEntry(
"toggleglobaltimer",302);
glutAddMenuEntry(
"toggleglobalanimation",303);
glutAddMenuEntry(
"toggleperwindowanimation",304);
glutAddMenuEntry(
"toggledebugprints(D)",305);
glutAddMenuEntry(
"toggleshadedbackdrop",307);
glutAddMenuEntry(
"togglepassivemotioncallback",308);
glutAddMenuEntry(
"increaselinewidth(l)",310);
glutAddMenuEntry(
"decreaselinewidth(L)",311);

/**//*Shapes*/

menu3
=glutCreateMenu(menuFunc);
glutAddMenuEntry(
"sphere",200);
glutAddMenuEntry(
"cube",201);
glutAddMenuEntry(
"cone",202);
glutAddMenuEntry(
"torus",203);
glutAddMenuEntry(
"dodecahedron",204);
glutAddMenuEntry(
"octahedron",205);
glutAddMenuEntry(
"tetrahedron",206);
glutAddMenuEntry(
"icosahedron",207);
glutAddMenuEntry(
"teapot",208);

/**//*Open/closewindows*/

menu4
=glutCreateMenu(menuFunc);
glutAddMenuEntry(
"openallwindows",450);
glutAddMenuEntry(
"closeallwindows",451);
glutAddMenuEntry(
"",9999);
glutAddMenuEntry(
"createwin0",400);
glutAddMenuEntry(
"createwin1",401);
glutAddMenuEntry(
"createwin2",402);
glutAddMenuEntry(
"createwin3",403);
glutAddMenuEntry(
"createsubwindow",404);
glutAddMenuEntry(
"createcolorindexwin6",406);
glutAddMenuEntry(
"createcolorindexwin7",407);
glutAddMenuEntry(
"",9999);
glutAddMenuEntry(
"destroywin0",410);
glutAddMenuEntry(
"destroywin1",411);
glutAddMenuEntry(
"destroywin2",412);
glutAddMenuEntry(
"destroywin3",413);
glutAddMenuEntry(
"destroysubwindow",414);
glutAddMenuEntry(
"destroycolorindexwin6",416);
glutAddMenuEntry(
"destroycolorindexwin7",417);

/**//*Windowmanagerstuff*/

menu5
=glutCreateMenu(menuFunc);
glutAddMenuEntry(
"movecurrentwin",430);
glutAddMenuEntry(
"resizecurrentwin",431);
glutAddMenuEntry(
"iconifycurrentwin",432);
glutAddMenuEntry(
"showcurrentwin",433);
glutAddMenuEntry(
"hidecurrentwin",434);
glutAddMenuEntry(
"pushcurrentwin",435);
glutAddMenuEntry(
"popcurrentwin",436);
glutAddMenuEntry(
"",9999);
glutAddMenuEntry(
"movewin1",420);
glutAddMenuEntry(
"resizewin1",421);
glutAddMenuEntry(
"iconifywin1",422);
glutAddMenuEntry(
"showwin1",423);
glutAddMenuEntry(
"hidewin1",424);
glutAddMenuEntry(
"pushwin1",425);
glutAddMenuEntry(
"popwin1",426);

/**//*Gfxmodes*/

createMenu6();
/**//*builddynamically*/

/**//*Textyreports*/

menu7
=glutCreateMenu(menuFunc);
glutAddMenuEntry(
"reportcurrentwinmodes",700);
glutAddMenuEntry(
"reportcurrentdevicedata",701);
glutAddMenuEntry(
"checkOpenGLextensions",702);
glutAddMenuEntry(
"dumpinternaldata(d)",703);

/**//*Playwithmenus*/

menu8
=glutCreateMenu(menuFunc);
glutAddMenuEntry(
"togglemenusonleftbutton",805);
glutAddMenuEntry(
"togglemenusonmiddlebutton",806);
glutAddMenuEntry(
"togglemenusonrightbutton",807);
glutAddMenuEntry(
"---------------------------",9999);
glutAddMenuEntry(
"addplainitems",800);
glutAddMenuEntry(
"addsubmenuitems",801);
glutAddMenuEntry(
"changenewentriestoplainitems",802);
glutAddMenuEntry(
"changenewentriestosubmenus",803);
glutAddMenuEntry(
"removeallnewitems",804);
glutAddMenuEntry(
"---------------------------",9999);

/**//*Mainmenu*/

menu1
=glutCreateMenu(menuFunc);
glutAddSubMenu(
"control",menu2);
glutAddSubMenu(
"shapes",menu3);
glutAddSubMenu(
"windows",menu4);
glutAddSubMenu(
"windowops",menu5);
glutAddSubMenu(
"gfxmodes",menu6);
glutAddSubMenu(
"reports",menu7);
glutAddSubMenu(
"menus",menu8);
glutAddMenuEntry(
"help(h)",101);
glutAddMenuEntry(
"quit(esc)",100);
}

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>-->voidmakeWindow(intindex)
{//建立窗口
charstr[99];

if(winId[index]!=0)
{//已经存在的窗口
/**//*warning("Attempttocreatewindowwhichisalready
created");
*/

return;
}

switch(index)
{
//普通的RGB窗口
case0:/**//*ordinaryRGBwindows*/
case1:
case2:
case3:

setInitDisplayMode();
glutInitWindowPosition(pos[index][
0],pos[index][1]);//窗口左上角位置
glutInitWindowSize(size[index][0],size[index][1]);//窗口大小
winId[index]=glutCreateWindow("");//保存窗口标识符
PR("Window%did=%d/n",index,winId[index]);
gfxInit(index);
//初始化openGL

addCallbacks();

sprintf(str,
"window%d(RGB)",index);
glutSetWindowTitle(str);
sprintf(str,
"icon%d",index);
glutSetIconTitle(str);
glutSetMenu(menu1);
glutAttachMenu(GLUT_RIGHT_BUTTON);
break;

case4:/**//*subwindow子窗口*/

setInitDisplayMode();
winId[index]
=glutCreateSubWindow(winId[0],pos[index][0],pos[index]
[
1],size[index][0],size[index][1]);
PR(
"Window%did=%d/n",index,winId[index]);
gfxInit(index);
glutDisplayFunc(drawScene);
glutVisibilityFunc(visible);
glutReshapeFunc(reshapeFunc);

break;

case5:/**//*helpwindow帮助窗口*/
case8:/**//*textwindow文本窗口*/
glutInitDisplayMode(GLUT_DOUBLE
|GLUT_RGB|GLUT_DEPTH);
glutInitWindowPosition(pos[index][
0],pos[index][1]);
glutInitWindowSize(size[index][
0],size[index][1]);
winId[index]
=glutCreateWindow("");
PR(
"Window%did=%d/n",index,winId[index]);

/**//*addCallbacks();*/
glutKeyboardFunc(keyFunc);
glutSpecialFunc(specialFunc);

glClearColor(
0.15,0.15,0.15,1.0);
glColor3f(
1,1,1);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluOrtho2D(
0,300,0,100);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();

if(index==5){
glutDisplayFunc(updateHelp);
glutSetWindowTitle(
"help(RGB)win5");
glutSetIconTitle(
"help");
}
else{
glutDisplayFunc(updateText);
glutSetWindowTitle(
"text(RGB)win8");
glutSetIconTitle(
"text");
}

glutSetMenu(menu1);
glutAttachMenu(GLUT_RIGHT_BUTTON);
break;

case6:/**//*colorindexwindow颜色索引窗口*/
case7:/**//*colorindexwindow*/

glutInitDisplayMode(GLUT_DOUBLE
|GLUT_INDEX|GLUT_DEPTH);
glutInitWindowPosition(pos[index][
0],pos[index][1]);
glutInitWindowSize(size[index][
0],size[index][1]);
winId[index]
=glutCreateWindow("");
PR(
"Window%did=%d/n",index,winId[index]);

gfxInit(index);

addCallbacks();

sprintf(str,
"window%d(colorindex)",index);
glutSetWindowTitle(str);
sprintf(str,
"icon%d",index);
glutSetIconTitle(str);
glutSetMenu(menu1);
glutAttachMenu(GLUT_RIGHT_BUTTON);
break;

}

}

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

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*/
voididleFunc(void)
{
inti;
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 字体来显示文本。

<!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>-->voidtextString(intx,inty,char*msg,void*font)
{
//显示文本,x,y是起始坐标,msg:要显示的文本,font:显示的字体
glRasterPos2f(x,y);//定位位图字体
while(*msg)
{
glutBitmapCharacter(font,
*msg);
msg
++;
}
}

/*strokeString-Strokefontstring*/
voidstrokeString(intx,inty,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轴的平移(产生缩放的效果)。鼠标的事件模式这里有RESETMOUSEBUTTONAPPLY 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;
}

}

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




分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics