这是susu给我的一份关于glut的示例代码,里面涉及到的内容有:用glut来完成菜单管理,文本显示,显示列表,材质,光照,多窗口显示,鼠标事件处理,键盘事件处理,菜单事件处理,窗口创建,缩放,销毁,动画播放,定时器等功能,运行效果如图:
我分成几个部分来对代码进行分析:
1,命令行参数检查
void checkArgs(int argc, char *argv[])
{
int argp;
GLboolean quit = GL_FALSE;
GLboolean error = GL_FALSE;
#define AA argv[argp]
argp = 1;
while (argp < argc)
{
if (match(AA, "-help"))
{
commandLineHelp();
quit = GL_TRUE;
}
else if (match(AA, "-version"))
printf(VERSIONLONG "\n");
else if (match(AA, "-auto"))
{//自动运行
demoMode = GL_TRUE;
else if (match(AA, "-scale"))
{//放缩
argp++;
scaleFactor = atof(argv[argp]);//设置缩放因子
else
{//出错处理
fprintf(stderr, "Unknown arg: %s\n", AA);
error = GL_TRUE;
}
argp++;
}
GLboolean match(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,窗口的缩放
通过对窗口原点和大小的调整就可以实现窗口的缩放。
int pos[MAXWIN][2] =
{//各个窗口的左上角坐标
{50, 150}, /* win 0 */
{450, 150}, /* win 1 */
{50, 600}, /* win 2 */
{450, 600}, /* win 3 */
{10, 10}, /* subwin 4 (relative to parent win 0) */
{300, 400}, /* help win 5 */
{850, 150}, /* cmap win 6 */
{850, 600}, /* cmap win 7 */
{250, 450} /* text win 8 */
};
int size[MAXWIN][2] =
{//各个窗口大小(宽度,高度)
{350, 350}, /* win 0 */
{350, 350}, /* win 1 */
{350, 350}, /* win 2 */
{350, 350}, /* win 3 */
{200, 200}, /* subwin 4 */
{700, 300}, /* help win 5 */
{350, 350}, /* cmap win 6 */
{350, 350}, /* cmap win 7 */
{800, 450} /* text win 8 */
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];通过这样的按位或运算最终获得窗口的显示模式。
int modes[MODES] ={0};
modes[RGBA] = 1;
modes[DOUBLEBUFFER] = 1;
modes[DEPTH] = 1;
setInitDisplayMode()
void setInitDisplayMode(void)
{//设置初始显示模式
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("This display mode not supported\n");
4,菜单管理
menu1到menu8这8个int型变量用来保存创建的菜单项,并且menu2到menu8都作为menu1的子菜单加入到menu1中。
创建菜单
5,创建窗口
本文中创建的窗口有4种类型,第1种是普通的RGB窗口,用来显示要绘制的图形,第2种是第1种窗口的子窗口(类似于“画中画”的效果),第3种是文本窗口和帮助窗口,第4种是颜色索引窗口。设置好窗口的显示模式,并根据保存的窗口大小和位置创建完窗口后,就可以对窗口进行OpenGL绘制的初始化工作,这是在gfxInit函数中完成的,最后就是为窗口加上各种事件处理函数。
创建窗口
为每个窗口初始化OpenGL时,首先通过redefineShapes为窗口建立其显示列表,然后渲染其背景矩阵,接着进行投影变换和视图变换,为了简单起见,作者采用了默认的白色光源来进行材质和光源位置的设置,最后就是启用光照并设置窗口的背景颜色。
OpenGL初始化
6,动画效果
我在MFC中是通过设置一个定时器,并且在定时方法中修改旋转角度来刷新屏幕的,从而实现动画旋转的效果,在这里作者把这部分代码放到窗口的空闲事件处理函数中进行。每次执行时角度都进行了变换,并且通知窗口强制其重绘。
/* idleFunc - GLUT idle func callback - animates windows */
void idleFunc(void)
if (!leftDown && !middleDown)//旋转角度加1
angle += 1;
angle = angle % 360;
if (winId[i] && winVis[i] && !winFreeze[i])
glutSetWindow(winId[i]);
glutPostRedisplay();//强制重画
7,自动演示
这里采用了一个小的技巧来实现多个窗口连续创建的自动演示功能。通过执行当前的动作后,为下一个应该接着发生的动作设置一个定时器,从而实现动作之间的接连发送效果。
旋转动画
8,图形绘制代码部分
所有窗口都使用drawScene来绘制其图形,只是各个窗口调用的显示列表不同而已,这通过各个窗口的标识符来进行区别,并且通过调用trackBall(APPLY, 0, 0, 0, 0);来绘制鼠标左键控制的结果(旋转后的角度或者平移后的距离),如果窗口还有文本要显示,则调用showText来显示文本信息。
图形绘制代码
9.文本显示
这里有两种文本的显示方式,第一种采用位图字体来显示文本,第二种采用Stroke 字体来显示文本。
void textString(int x, int y, char *msg, void *font)
{//显示文本,x,y是起始坐标,msg:要显示的文本,font:显示的字体
glRasterPos2f(x, y);//定位位图字体
while (*msg)
glutBitmapCharacter(font, *msg);
msg++;
/* strokeString - Stroke font string */
void strokeString(int x, int y, char *msg, void *font)
glPushMatrix();
glTranslatef(x, y, 0);
glScalef(.04, .04, .04);
while (*msg)
glutStrokeCharacter(font, *msg);
glPopMatrix();
10,显示列表
显示列表由于是已经编译好的代码段,因此可以加快程序的速度。这里每种要绘制的图形(如球,茶壶等)都有实体和虚体两种模式可以选择。
显示列表
11,鼠标事件处理
这里鼠标有三种控制方式,1)左键进行旋转。2)中键进行xy平面的平移。3)左键+中键进行关于Z轴的平移(产生缩放的效果)。鼠标的事件模式这里有RESET,MOUSEBUTTON,APPLY, MOUSEMOTION四种,其中RESET是用来对清空以往的操作,让图形回到原点处。MOUSEBUTTON是鼠标按下激发的,用来记录下鼠标的位置,MOUSEMOTION是鼠标按下后并移动鼠标时,用来计算旋转的角度或者平移的距离,而最终这些变换后产生的效果的绘制是APPLY发生的,在这里进行了实际的旋转和平移动作。
鼠标控制
最后,代码中还加入了对空间球,图形板,拨号按键盒的事件处理支持。